Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package tuned for openSUSE:Factory checked 
in at 2025-09-10 20:22:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/tuned (Old)
 and      /work/SRC/openSUSE:Factory/.tuned.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "tuned"

Wed Sep 10 20:22:41 2025 rev:48 rq:1303530 version:2.26.0.0+git.181472a

Changes:
--------
--- /work/SRC/openSUSE:Factory/tuned/tuned.changes      2025-06-02 
22:01:20.987185031 +0200
+++ /work/SRC/openSUSE:Factory/.tuned.new.1977/tuned.changes    2025-09-10 
20:22:43.666446094 +0200
@@ -1,0 +2,41 @@
+Wed Sep 10 07:01:06 UTC 2025 - Thomas Renninger <[email protected]>
+
+- Update to version 2.26.0.0+git.181472a:
+  * new release (2.26.0)
+  * new release (2.26.0-rc.1)
+  * fix: add no_turbo option in profiles where boost is used
+  * If plugin isn't supported, log details why it isn't supported
+  * Fixed instance priority inheritance
+  * functions: Make calc_isolated_cores return CPU ranges
+  * Allow overriding the no_turbo setting
+  * udev: fix possible traceback in device matcher
+  * vm: Deprecate dirty_ratio in favour of dirty_bytes with %
+  * tuned-ppd: Pin virtual files in memory for inotify
+  * tuned-ppd: Fix indentation
+  * tuned-ppd: Fix inotify watch for performance degradation
+  * Dockerfile: New to build on a bootc image
+  * bootloader: Remove previously appended rpm-ostree kargs
+  * bootloader: Simplify tuning of rpm-ostree kargs
+  * udev-settle: obey udev buffer size and handle possible tracebacks
+  * plugins: Support MMC devices
+  * CI: build and test for c10s
+  * tests/beakerlib: remove old API call.
+  * spec: minor spec cleanup and enabled doc install on RHEL
+  * tuned-main.conf: added startup_udev_settle_wait option
+  * consts: fixed whitespaces
+  * Re-raise daemon init exception in no-daemon mode
+  * scsi: Do not set ALPM on external SATA ports
+  * realtime: Disable appropriate P-State drivers
+  * beakerlib: Use ncat explicitly instead of nc
+  * hotplug: fixed device remove race condition
+  * perf: dropped from irqbalance and improved detection in scheduler
+  * variables: Add an option to prepend child variables before parent ones
+  * ppd: Enable sysfs_acpi_monitor by default
+  * GUI: Fix the profile deleter script
+  * functions: Silence errors if module kvm_intel does not exist
+  * ppd: Rename thinkpad_function_keys as sysfs_acpi_monitor
+  * network_latency: Set non-zero rcutree.nohz_full_patience_delay
+  * profiles: use `med_power_with_dipm` for SATA ALPM Using `min_power` can 
lead to data loss, and `med_power_with_dipm` delivers similar power savings 
without the chance of data loss. [1]
+  * plugins: document `med_power_with_dipm` SATA ALPM option The use of 
`min_power` can lead to data corruption[1] and has been replaced in the 
documentation, and an example using `medium_power` was updated to use 
`med_power_with_dipm` (the kernel default[2] with better better power savings 
than `medium_power`).
+
+-------------------------------------------------------------------

Old:
----
  tuned-2.25.1.0+git.889387b.obscpio

New:
----
  tuned-2.26.0.0+git.181472a.obscpio

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

Other differences:
------------------
++++++ tuned.spec ++++++
--- /var/tmp/diff_new_pack.3m0nyP/_old  2025-09-10 20:22:44.750491856 +0200
+++ /var/tmp/diff_new_pack.3m0nyP/_new  2025-09-10 20:22:44.754492025 +0200
@@ -19,7 +19,7 @@
 %define         system_dir %{_prefix}/lib/%{name}/
 %define         profile_dir %{system_dir}profiles/
 Name:           tuned
-Version:        2.25.1.0+git.889387b
+Version:        2.26.0.0+git.181472a
 Release:        0
 Summary:        A dynamic adaptive system tuning daemon
 License:        GPL-2.0-or-later

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.3m0nyP/_old  2025-09-10 20:22:44.798493882 +0200
+++ /var/tmp/diff_new_pack.3m0nyP/_new  2025-09-10 20:22:44.802494051 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/redhat-performance/tuned</param>
-              <param 
name="changesrevision">889387b0001b783514523162de21af406e31a549</param></service></servicedata>
+              <param 
name="changesrevision">181472a0be2125c8cd36c7673ec546d75d396a3d</param></service></servicedata>
 (No newline at EOF)
 

++++++ tuned-2.25.1.0+git.889387b.obscpio -> tuned-2.26.0.0+git.181472a.obscpio 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/.dockerignore 
new/tuned-2.26.0.0+git.181472a/.dockerignore
--- old/tuned-2.25.1.0+git.889387b/.dockerignore        1970-01-01 
01:00:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/.dockerignore        2025-08-24 
23:48:04.000000000 +0200
@@ -0,0 +1,2 @@
+# Avoid rebuilding when this changes
+Dockerfile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/.github/workflows/docker-build.yml 
new/tuned-2.26.0.0+git.181472a/.github/workflows/docker-build.yml
--- old/tuned-2.25.1.0+git.889387b/.github/workflows/docker-build.yml   
1970-01-01 01:00:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/.github/workflows/docker-build.yml   
2025-08-24 23:48:04.000000000 +0200
@@ -0,0 +1,22 @@
+name: Docker Build
+
+on:
+  workflow_dispatch:
+  pull_request:
+    branches: [ "main" ]
+
+jobs:
+  build:
+    runs-on: ubuntu-24.04
+    steps:
+      - name: Get a newer podman for heredoc support (from debian testing)
+        run: |
+          set -eux
+          echo 'deb [trusted=yes] https://ftp.debian.org/debian/ testing main' 
| sudo tee /etc/apt/sources.list.d/testing.list
+          sudo apt update
+          sudo apt install -y crun/testing podman/testing skopeo/testing
+
+      - uses: actions/checkout@v4
+
+      - name: Build container
+        run: sudo podman build -t localhost/tuned .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/.packit.yaml 
new/tuned-2.26.0.0+git.181472a/.packit.yaml
--- old/tuned-2.25.1.0+git.889387b/.packit.yaml 2025-02-03 20:17:00.000000000 
+0100
+++ new/tuned-2.26.0.0+git.181472a/.packit.yaml 2025-08-24 23:48:04.000000000 
+0200
@@ -8,6 +8,7 @@
   - epel-7-x86_64
   - epel-8-x86_64
   - centos-stream-9-x86_64
+  - centos-stream-10-x86_64
 - job: tests
   trigger: pull_request
   targets:
@@ -15,6 +16,7 @@
   - epel-7-x86_64
   - epel-8-x86_64
   - centos-stream-9-x86_64
+  - centos-stream-10-x86_64
 
 files_to_sync:
 - tuned.spec
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/Dockerfile 
new/tuned-2.26.0.0+git.181472a/Dockerfile
--- old/tuned-2.25.1.0+git.889387b/Dockerfile   1970-01-01 01:00:00.000000000 
+0100
+++ new/tuned-2.26.0.0+git.181472a/Dockerfile   2025-08-24 23:48:04.000000000 
+0200
@@ -0,0 +1,30 @@
+ARG base=quay.io/centos-bootc/centos-bootc:stream10
+
+FROM $base as build
+COPY tuned.spec /tmp/tuned.spec
+# This installs our package dependencies, and we want to cache it 
independently of the rest.
+RUN <<EORUN
+set -xeuo pipefail
+dnf -y install rpm-build
+dnf -y builddep /tmp/tuned.spec
+EORUN
+# Now copy the rest of the source
+COPY . /build
+WORKDIR /build
+RUN <<EORUN
+set -xeuo pipefail
+mkdir -p /var/roothome
+make rpm
+mkdir -p /out
+mv ~/rpmbuild/RPMS/noarch/tuned-2*.rpm /out
+EORUN
+
+FROM $base
+RUN --mount=from=build,target=/build,type=bind <<EORUN
+set -xeuo pipefail
+dnf -y install /build/out/*.rpm
+dnf clean all
+rm -rf /var/{lib,cache,log}/*
+bootc container lint --fatal-warnings
+EORUN
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc
 
new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc
--- 
old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc
   2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc
   2025-08-24 23:48:04.000000000 +0200
@@ -22,14 +22,14 @@
 
 .A power-saving profile based on balanced
 ====
-The following is an example of a custom profile that extends the `balanced` 
profile and sets Aggressive Link Power Management (ALPM) for all devices to the 
maximum powersaving.
+The following is an example of a custom profile that extends the `balanced` 
profile and disables the capability of the CPU to boost above nominal 
frequencies for brief periods.
 
 ----
 [main]
 include=balanced
 
-[scsi_host]
-alpm=min_power
+[cpu]
+boost=0
 ----
 ====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc
 
new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc
--- 
old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc
 2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc
 2025-08-24 23:48:04.000000000 +0200
@@ -43,7 +43,7 @@
 radeon_powersave=dpm-balanced, auto
 
 [scsi_host]
-alpm=medium_power
+alpm=med_power_with_dipm
 ----
 
 . To activate the profile, use:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/functions 
new/tuned-2.26.0.0+git.181472a/functions
--- old/tuned-2.25.1.0+git.889387b/functions    2025-02-03 20:17:00.000000000 
+0100
+++ new/tuned-2.26.0.0+git.181472a/functions    2025-08-24 23:48:04.000000000 
+0200
@@ -477,7 +477,7 @@
 
        modinfo -p kvm | grep -q kvmclock_periodic_sync && HAS_KPS=1
        modinfo -p kvm | grep -q nx_huge_pages && HAS_NX_HP=1
-       modinfo -p kvm_intel | grep -q ple_gap && HAS_PLE_GAP=1
+       modinfo -p kvm_intel 2>/dev/null | grep -q ple_gap && HAS_PLE_GAP=1
        grep -qs kvmclock_periodic_sync "$kvm_modprobe_file" && WANTS_KPS=1
        grep -qs nx_huge_pages "$kvm_modprobe_file" && WANTS_NX_HP=1
        grep -qs ple_gap "$kvm_modprobe_file" && WANTS_PLE_GAP=1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/accelerator-performance/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/accelerator-performance/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/accelerator-performance/tuned.conf  
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/accelerator-performance/tuned.conf  
2025-08-24 23:48:04.000000000 +0200
@@ -25,11 +25,11 @@
 #
 # The generator of dirty data starts writeback at this percentage (system 
default
 # is 20%)
-dirty_ratio = 40
+dirty_bytes = 40%
 
 # Start background writeback (via writeback threads) at this percentage (system
 # default is 10%)
-dirty_background_ratio = 10
+dirty_background_bytes = 10%
 
 [sysctl]
 # PID allocation wrap value.  When the kernel's next PID value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/balanced/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/balanced/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/balanced/tuned.conf 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/balanced/tuned.conf 2025-08-24 
23:48:04.000000000 +0200
@@ -30,4 +30,4 @@
 # devices=sda
 
 [scsi_host]
-alpm=medium_power
+alpm=med_power_with_dipm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf
 
new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf
--- 
old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf
        2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf
        2025-08-24 23:48:04.000000000 +0200
@@ -12,3 +12,7 @@
 # given to force_latency tuned parameter. To have the same behavior
 # as cpu-partitioning profile, set to "cstate.name:C1|10"
 max_power_state=cstate.name:C1|10
+
+# If set to true, disables turbo mode on all CPUs.
+# This is useful for power saving, but may reduce performance.
+no_turbo=true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/tuned.conf
--- 
old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/tuned.conf   
    2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/tuned.conf   
    2025-08-24 23:48:04.000000000 +0200
@@ -25,7 +25,7 @@
 
 [cpu]
 force_latency=${max_power_state}
-no_turbo=true
+no_turbo=${no_turbo}
 
 [bootloader]
 cmdline_cpu_part=+nohz=on${cmd_isolcpus} nohz_full=${isolated_cores} 
rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} 
intel_pstate=passive nosoftlockup
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/latency-performance/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/latency-performance/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/latency-performance/tuned.conf      
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/latency-performance/tuned.conf      
2025-08-24 23:48:04.000000000 +0200
@@ -22,11 +22,11 @@
 #
 # The generator of dirty data starts writeback at this percentage (system 
default
 # is 20%)
-dirty_ratio=10
+dirty_bytes=10%
 
 # Start background writeback (via writeback threads) at this percentage (system
 # default is 10%)
-dirty_background_ratio=3
+dirty_background_bytes=3%
 
 [sysctl]
 # The swappiness parameter controls the tendency of the kernel to move
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/mssql/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/mssql/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/mssql/tuned.conf    2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/mssql/tuned.conf    2025-08-24 
23:48:04.000000000 +0200
@@ -12,8 +12,8 @@
 [vm]
 # For multi-instance SQL deployments use 'madvise' instead of 'always'
 transparent_hugepages=always
-dirty_background_ratio=3
-dirty_ratio=80
+dirty_background_bytes=3%
+dirty_bytes=80%
 
 [sysctl]
 vm.swappiness=1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/network-latency/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/network-latency/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/network-latency/tuned.conf  
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/network-latency/tuned.conf  
2025-08-24 23:48:04.000000000 +0200
@@ -20,6 +20,6 @@
 kernel.timer_migration = 0
 
 [bootloader]
-cmdline_network_latency=skew_tick=1 tsc=reliable 
rcupdate.rcu_normal_after_boot=1
+cmdline_network_latency=skew_tick=1 tsc=reliable 
rcupdate.rcu_normal_after_boot=1 rcutree.nohz_full_patience_delay=1000
 
 [rtentsk]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/oracle/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/oracle/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/oracle/tuned.conf   2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/oracle/tuned.conf   2025-08-24 
23:48:04.000000000 +0200
@@ -25,6 +25,6 @@
 kernel.numa_balancing = 0
 
 [vm]
-dirty_background_ratio = 3
-dirty_ratio = 40
+dirty_background_bytes = 3%
+dirty_bytes = 40%
 transparent_hugepages=never
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/powersave/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/powersave/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/powersave/tuned.conf        
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/powersave/tuned.conf        
2025-08-24 23:48:04.000000000 +0200
@@ -34,7 +34,7 @@
 # devices=eth0
 
 [scsi_host]
-alpm=min_power
+alpm=med_power_with_dipm
 
 [sysctl]
 vm.laptop_mode=5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/realtime/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/realtime/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/realtime/tuned.conf 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/realtime/tuned.conf 2025-08-24 
23:48:04.000000000 +0200
@@ -11,6 +11,9 @@
 # User is responsible for updating variables.conf with variable content such 
as isolated_cores=X-Y 
 include = /etc/tuned/realtime-variables.conf
 
+# Disable appropriate P-State drivers (intel_pstate or amd_pstate)
+disable_pstate = 
${f:cpuinfo_check:GenuineIntel:intel_pstate=disable:AuthenticAMD:amd_pstate=disable:}
+
 isolated_cores_assert_check = \\${isolated_cores}
 # Make sure isolated_cores is defined before any of the variables that
 # use it (such as assert1) are defined, so that child profiles can set
@@ -48,7 +51,7 @@
 /sys/devices/system/machinecheck/machinecheck*/ignore_ce = 1
 
 [bootloader]
-cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} 
intel_pstate=disable nosoftlockup
+cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} ${disable_pstate} 
nosoftlockup
 
 [irqbalance]
 banned_cpus=${isolated_cores}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/sap-hana/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/sap-hana/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/sap-hana/tuned.conf 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/sap-hana/tuned.conf 2025-08-24 
23:48:04.000000000 +0200
@@ -13,8 +13,8 @@
 
 [vm]
 transparent_hugepages=madvise
-dirty_ratio = 40
-dirty_background_ratio = 10
+dirty_bytes = 40%
+dirty_background_bytes = 10%
 
 [sysctl]
 kernel.sem = 32000 1024000000 500 32000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/server-powersave/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/server-powersave/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/server-powersave/tuned.conf 
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/server-powersave/tuned.conf 
2025-08-24 23:48:04.000000000 +0200
@@ -11,4 +11,4 @@
 [disk]
 
 [scsi_host]
-alpm=min_power
+alpm=med_power_with_dipm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/spectrumscale-ece/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/spectrumscale-ece/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/spectrumscale-ece/tuned.conf        
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/spectrumscale-ece/tuned.conf        
2025-08-24 23:48:04.000000000 +0200
@@ -12,8 +12,8 @@
 min_perf_pct=100
 
 [vm]
-dirty_ratio = 40
-dirty_background_ratio = 10
+dirty_bytes = 40%
+dirty_background_bytes = 10%
 
 [sysctl]
 kernel.numa_balancing = 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/spindown-disk/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/spindown-disk/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/spindown-disk/tuned.conf    
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/spindown-disk/tuned.conf    
2025-08-24 23:48:04.000000000 +0200
@@ -24,10 +24,10 @@
 spindown=6
 
 [scsi_host]
-alpm=medium_power
+alpm=med_power_with_dipm
 
 [vm]
-dirty_ratio=60
+dirty_bytes=60%
 
 [sysctl]
 vm.dirty_writeback_centisecs=6000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/throughput-performance/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/throughput-performance/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/throughput-performance/tuned.conf   
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/throughput-performance/tuned.conf   
2025-08-24 23:48:04.000000000 +0200
@@ -25,11 +25,11 @@
 #
 # The generator of dirty data starts writeback at this percentage (system 
default
 # is 20%)
-dirty_ratio = 40
+dirty_bytes = 40%
 
 # Start background writeback (via writeback threads) at this percentage (system
 # default is 10%)
-dirty_background_ratio = 10
+dirty_background_bytes = 10%
 
 # Marvell ThunderX
 [vm.thunderx]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/virtual-guest/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/virtual-guest/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/virtual-guest/tuned.conf    
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/virtual-guest/tuned.conf    
2025-08-24 23:48:04.000000000 +0200
@@ -14,7 +14,7 @@
 #
 # The generator of dirty data starts writeback at this percentage (system 
default
 # is 20%)
-dirty_ratio = 30
+dirty_bytes = 30%
 
 [sysctl]
 # Filesystem I/O is usually much more efficient than swapping, so try to keep
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/profiles/virtual-host/tuned.conf 
new/tuned-2.26.0.0+git.181472a/profiles/virtual-host/tuned.conf
--- old/tuned-2.25.1.0+git.889387b/profiles/virtual-host/tuned.conf     
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/profiles/virtual-host/tuned.conf     
2025-08-24 23:48:04.000000000 +0200
@@ -9,7 +9,7 @@
 [vm]
 # Start background writeback (via writeback threads) at this percentage (system
 # default is 10%)
-dirty_background_ratio = 5
+dirty_background_bytes = 5%
 
 [cpu]
 # Setting C3 state sleep mode/power savings
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh
 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh
--- 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh
        2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh
        2025-08-24 23:48:04.000000000 +0200
@@ -24,7 +24,7 @@
   local socket=/run/tuned/tuned.sock
 #  local send_only=--send-only
   
-  printf "$data" | nc $send_only -U /run/tuned/tuned.sock
+  printf "$data" | ncat $send_only -U /run/tuned/tuned.sock
 }
 
 rlJournalStart
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf
 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf
--- 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf
    2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf
    2025-08-24 23:48:04.000000000 +0200
@@ -2,4 +2,4 @@
 summary=Post-loaded profile
 
 [vm]
-dirty_ratio=8
+dirty_bytes=8%
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf
 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf
--- 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf
       2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf
       2025-08-24 23:48:04.000000000 +0200
@@ -2,4 +2,4 @@
 summary=Post-loaded profile that uses variables from the regular active profile
 
 [vm]
-dirty_ratio=${foo}
+dirty_bytes=${foo}%
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf
 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf
--- 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf
   2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf
   2025-08-24 23:48:04.000000000 +0200
@@ -2,4 +2,4 @@
 summary=Second version of the post-loaded profile
 
 [vm]
-dirty_ratio=7
+dirty_bytes=7%
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tests/beakerlib/error-messages/runtest.sh 
new/tuned-2.26.0.0+git.181472a/tests/beakerlib/error-messages/runtest.sh
--- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/error-messages/runtest.sh    
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/error-messages/runtest.sh    
2025-08-24 23:48:04.000000000 +0200
@@ -24,16 +24,18 @@
         rlAssertRpm $PACKAGE
         rlImport "tuned/basic"
 
-        PROFILE_DIR=$(tunedGetSystemProfilesBaseDir)
+        rlServiceStart "tuned"
+        tunedProfileBackup
 
         rlFileBackup "/var/log/tuned/tuned.log"
+
         tunedDisableSystemdRateLimitingStart
-        rlServiceStart "tuned"
-        tunedProfileBackup
+
+        USRPROFILEDIR="$(tunedGetUsrProfilesBaseDir)"
     rlPhaseEnd
 
     rlPhaseStartTest "Test of profile balanced"
-        rlRun "cat $PROFILE_DIR/balanced/tuned.conf | grep alpm="
+        rlRun "cat ${USRPROFILEDIR}/balanced/tuned.conf | grep alpm="
         echo > /var/log/tuned/tuned.log
         rlRun "tuned-adm profile balanced"
         rlRun "tuned-adm active | grep balanced"
@@ -42,7 +44,7 @@
     rlPhaseEnd
 
     rlPhaseStartTest "Test of profile powersave"
-        rlRun "cat $PROFILE_DIR/powersave/tuned.conf | grep alpm="
+        rlRun "cat ${USRPROFILEDIR}/powersave/tuned.conf | grep alpm="
         echo > /var/log/tuned/tuned.log
         rlRun "tuned-adm profile powersave"
         rlRun "tuned-adm active | grep powersave"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/admin/admin.py 
new/tuned-2.26.0.0+git.181472a/tuned/admin/admin.py
--- old/tuned-2.25.1.0+git.889387b/tuned/admin/admin.py 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/admin/admin.py 2025-08-24 
23:48:04.000000000 +0200
@@ -303,7 +303,7 @@
                print("Trying to (re)start tuned...")
                (ret, msg) = self._cmd.execute(["service", "tuned", "restart"])
                if ret != 0:
-                       raise TunedException("TuneD (re)start failed, you need 
to (re)start TuneD by hand.")
+                       raise TunedException("TuneD (re)start failed, check 
TuneD logs for details.")
                print("TuneD (re)started.")
 
        def _set_profile(self, profile_name, manual):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/consts.py 
new/tuned-2.26.0.0+git.181472a/tuned/consts.py
--- old/tuned-2.25.1.0+git.889387b/tuned/consts.py      2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/consts.py      2025-08-24 
23:48:04.000000000 +0200
@@ -21,6 +21,7 @@
 SYSTEM_PROFILES_DIR = "/usr/lib/tuned/profiles"
 PERSISTENT_STORAGE_DIR = "/var/lib/tuned"
 PLUGIN_MAIN_UNIT_NAME = "main"
+PLUGIN_VARIABLES_UNIT_NAME = "variables"
 # Magic section header because ConfigParser does not support "headerless" 
config
 MAGIC_HEADER_NAME = 
"this_is_some_magic_section_header_because_of_compatibility"
 RECOMMEND_DIRECTORIES = ["/usr/lib/tuned/recommend.d", 
"/etc/tuned/recommend.d"]
@@ -43,7 +44,6 @@
 INITRD_IMAGE_DIR = "/boot"
 BOOT_CMDLINE_TUNED_VAR = "TUNED_BOOT_CMDLINE"
 BOOT_CMDLINE_INITRD_ADD_VAR = "TUNED_BOOT_INITRD_ADD"
-BOOT_CMDLINE_KARGS_DELETED_VAR = "TUNED_BOOT_KARGS_DELETED"
 BOOT_CMDLINE_FILE = "/etc/tuned/bootcmdline"
 PETITBOOT_DETECT_DIR = "/sys/firmware/opal"
 MACHINE_ID_FILE = "/etc/machine-id"
@@ -106,17 +106,17 @@
 PPD_DBUS_BUS = "org.freedesktop.UPower.PowerProfiles"
 PPD_DBUS_BUS_LEGACY = "net.hadess.PowerProfiles"
 PPD_DBUS_NAMES = [
-    {
-        "bus": PPD_DBUS_BUS,
-        "namespace": PPD_DBUS_BUS,
-        "interface": PPD_DBUS_BUS,
-        "object": "/org/freedesktop/UPower/PowerProfiles"
+       {
+               "bus": PPD_DBUS_BUS,
+               "namespace": PPD_DBUS_BUS,
+               "interface": PPD_DBUS_BUS,
+               "object": "/org/freedesktop/UPower/PowerProfiles"
        },
-    {
-        "bus": PPD_DBUS_BUS_LEGACY,
-        "namespace": PPD_DBUS_BUS_LEGACY,
-        "interface": PPD_DBUS_BUS_LEGACY,
-        "object": "/net/hadess/PowerProfiles"
+       {
+               "bus": PPD_DBUS_BUS_LEGACY,
+               "namespace": PPD_DBUS_BUS_LEGACY,
+               "interface": PPD_DBUS_BUS_LEGACY,
+               "object": "/net/hadess/PowerProfiles"
        }
 ]
 
@@ -146,6 +146,7 @@
 CFG_CPU_EPP_FLAG = "hwp_epp"
 CFG_ROLLBACK = "rollback"
 CFG_PROFILE_DIRS = "profile_dirs"
+CFG_STARTUP_UDEV_SETTLE_WAIT = "startup_udev_settle_wait"
 
 # no_daemon mode
 CFG_DEF_DAEMON = True
@@ -197,6 +198,8 @@
 CFG_DEF_ROLLBACK = "auto"
 # default profile directories
 CFG_DEF_PROFILE_DIRS = [SYSTEM_PROFILES_DIR, USER_PROFILES_DIR]
+# default startup udev settle wait
+CFG_DEF_STARTUP_UDEV_SETTLE_WAIT = 0
 
 PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/daemon/controller.py 
new/tuned-2.26.0.0+git.181472a/tuned/daemon/controller.py
--- old/tuned-2.25.1.0+git.889387b/tuned/daemon/controller.py   2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/daemon/controller.py   2025-08-24 
23:48:04.000000000 +0200
@@ -6,6 +6,8 @@
 import tuned.consts as consts
 from tuned.utils.commands import commands
 from tuned.plugins import hotplug
+import pyudev
+import time
 
 __all__ = ["Controller"]
 
@@ -54,13 +56,39 @@
                Controller main loop. The call is blocking.
                """
                log.info("starting controller")
+               self._terminate.clear()
+               wait_settle = 
self._global_config.get_int(consts.CFG_STARTUP_UDEV_SETTLE_WAIT, \
+                       consts.CFG_DEF_STARTUP_UDEV_SETTLE_WAIT)
+               if wait_settle > 0:
+                       log.info("waiting for udev to settle")
+                       monitor = pyudev.Monitor.from_netlink(pyudev.Context())
+                       udev_buffer_size = 
self._global_config.get_size("udev_buffer_size", 
consts.CFG_DEF_UDEV_BUFFER_SIZE)
+                       try:
+                               
monitor.set_receive_buffer_size(udev_buffer_size)
+                       except EnvironmentError:
+                               log.warning("cannot set udev monitor receive 
buffer size, we are probably running inside " +
+                                        "container or with limited 
capabilites, TuneD functionality may be limited")
+                       p = True
+                       t = time.time()
+                       try:
+                               while time.time() < (t + wait_settle) and not 
self._terminate.is_set() and p:
+                                       p = monitor.poll(timeout = 1)
+                               if not self._terminate.is_set():
+                                       if p:
+                                               log.info("udev settle timed 
out")
+                                       else:
+                                               log.info("udev settled")
+                       # https://github.com/pyudev/pyudev/issues/194
+                       except (OSError, IOError) as e:
+                               log.warning("udev settle failed, '%s'" % e)
+                       del monitor
+
                res = self.start()
                daemon = self._global_config.get_bool(consts.CFG_DAEMON, 
consts.CFG_DEF_DAEMON)
                if not res and daemon:
                        exports.start()
 
                if daemon:
-                       self._terminate.clear()
                        # we have to pass some timeout, otherwise signals will 
not work
                        while not self._cmd.wait(self._terminate, 1):
                                exports.period_check()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/daemon/daemon.py 
new/tuned-2.26.0.0+git.181472a/tuned/daemon/daemon.py
--- old/tuned-2.25.1.0+git.889387b/tuned/daemon/daemon.py       2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/daemon/daemon.py       2025-08-24 
23:48:04.000000000 +0200
@@ -51,6 +51,8 @@
                        self._init_profile(profile_names)
                except TunedException as e:
                        log.error("Cannot set initial profile. No tunings will 
be enabled: %s" % e)
+                       if not self._daemon:
+                               raise TunedException("Applying TuneD profile 
failed, check TuneD logs for details.")
 
        def _init_threads(self):
                self._thread = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/gtk/gui_profile_deleter.py 
new/tuned-2.26.0.0+git.181472a/tuned/gtk/gui_profile_deleter.py
--- old/tuned-2.25.1.0+git.889387b/tuned/gtk/gui_profile_deleter.py     
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/gtk/gui_profile_deleter.py     
2025-08-24 23:48:04.000000000 +0200
@@ -2,6 +2,12 @@
 import sys
 import shutil
 
+import tuned.consts
+
 if __name__ == '__main__':
 
-       shutil.rmtree('/etc/tuned/%s' % 
(os.path.basename(os.path.abspath(sys.argv[1]))))
+    shutil.rmtree(
+        os.path.join(
+            tuned.consts.USER_PROFILES_DIR,
+            os.path.basename(os.path.abspath(sys.argv[1]))
+    ))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/hardware/device_matcher_udev.py 
new/tuned-2.26.0.0+git.181472a/tuned/hardware/device_matcher_udev.py
--- old/tuned-2.25.1.0+git.889387b/tuned/hardware/device_matcher_udev.py        
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/hardware/device_matcher_udev.py        
2025-08-24 23:48:04.000000000 +0200
@@ -16,7 +16,10 @@
                try:
                        items = device.properties.items()
                except AttributeError:
-                       items = device.items()
+                       try:
+                               items = device.items()
+                       except AttributeError:
+                               return False
 
                for key, val in sorted(list(items)):
                        properties += key + '=' + val + '\n'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/hotplug.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/hotplug.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/hotplug.py     2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/hotplug.py     2025-08-24 
23:48:04.000000000 +0200
@@ -13,8 +13,8 @@
                super(Plugin, self).__init__(*args, **kwargs)
 
        def cleanup(self):
-               super(Plugin, self).cleanup()
                self._hardware_events_cleanup()
+               super(Plugin, self).cleanup()
 
        def _hardware_events_init(self):
                pass
@@ -46,6 +46,7 @@
 
        def _add_device(self, device_name):
                if device_name in (self._assigned_devices | self._free_devices):
+                       log.debug("device: '%s' already exists, ignoring" % 
device_name)
                        return
 
                for instance_name, instance in list(self._instances.items()):
@@ -102,13 +103,17 @@
 
                """
                if device_name not in (self._assigned_devices | 
self._free_devices):
+                       log.debug("device: '%s' doesn't exist, ignoring" % 
device_name)
                        return
 
                for instance in list(self._instances.values()):
                        if self._remove_device_process(instance, device_name):
                                break
                else:
-                       self._free_devices.remove(device_name)
+                       try:
+                               self._free_devices.remove(device_name)
+                       except KeyError:
+                               log.debug("device: '%s' isn't initialized, not 
removing it" % device_name)
 
        def _remove_devices_nocheck(self, instance, device_names):
                """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_bootloader.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_bootloader.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_bootloader.py   
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_bootloader.py   
2025-08-24 23:48:04.000000000 +0200
@@ -105,7 +105,7 @@
        ----
        [main]
        include=profile_1
-       
+
        [bootloader]
        cmdline_profile_2=-quiet
        ----
@@ -114,7 +114,7 @@
        ----
        [main]
        include=profile_1
-       
+
        [bootloader]
        cmdline_profile_1=-quiet
        ----
@@ -209,24 +209,6 @@
                        "skip_grub_config": None,
                }
 
-       @staticmethod
-       def _options_to_dict(options, omit=""):
-               """
-               Returns dict created from options
-               e.g.: _options_to_dict("A=A A=B A B=A C=A", "A=B B=A B=B") 
returns {'A': ['A', None], 'C': ['A']}
-               """
-               d = {}
-               omit = omit.split()
-               for o in options.split():
-                       if o not in omit:
-                               arr = o.split('=', 1)
-                               d.setdefault(arr[0], []).append(arr[1] if 
len(arr) > 1 else None)
-               return d
-
-       @staticmethod
-       def _dict_to_options(d):
-               return " ".join([k + "=" + v1 if v1 is not None else k for k, v 
in d.items() for v1 in v])
-
        def _rpm_ostree_status(self):
                """
                Returns status of rpm-ostree transactions or None if not run on 
rpm-ostree system
@@ -241,68 +223,45 @@
                        return None
                return splited[1]
 
-       def _wait_till_idle(self):
+       def _wait_till_rpm_ostree_idle(self):
+               """Check that rpm-ostree is idle, allowing some waiting time."""
                sleep_cycles = 10
                sleep_secs = 1.0
-               for i in range(sleep_cycles):
+               for _ in range(sleep_cycles):
                        if self._rpm_ostree_status() == "idle":
                                return True
                        sleep(sleep_secs)
-               if self._rpm_ostree_status() == "idle":
-                       return True
-               return False
+               return self._rpm_ostree_status() == "idle"
 
-       def _rpm_ostree_kargs(self, append={}, delete={}):
-               """
-               Method for appending or deleting rpm-ostree karg
-               returns None if rpm-ostree not present or is run on not ostree 
system
-               or tuple with new kargs, appended kargs and deleted kargs
-               """
-               (rc, out, err) = self._cmd.execute(['rpm-ostree', 'kargs'], 
return_err=True)
-               log.debug("rpm-ostree output stdout:\n%s\nstderr:\n%s" % (out, 
err))
+       def _get_rpm_ostree_kargs(self):
+               """Retrieve the output of rpm-ostree kargs, i.e., current 
default kernel arguments."""
+               if not self._wait_till_rpm_ostree_idle():
+                       log.error("Error getting rpm-ostree kargs: rpm-ostree 
is busy")
+                       return None
+               (rc, out, err) = self._cmd.execute(["rpm-ostree", "kargs"], 
return_err=True)
+               if out:
+                       log.debug("rpm-ostree kargs: %s" % out)
                if rc != 0:
-                       return None, None, None
-               kargs = self._options_to_dict(out)
+                       log.error("Error getting rpm-ostree kargs: %s" % err)
+                       return None
+               return out
 
-               if not self._wait_till_idle():
-                       log.error("Cannot wait for transaction end")
-                       return None, None, None
-
-               deleted = {}
-               delete_params = self._dict_to_options(delete).split()
-               # Deleting kargs, e.g. deleting added kargs by profile
-               for k, val in delete.items():
-                       for v in val:
-                               kargs[k].remove(v)
-                       deleted[k] = val
-
-               appended = {}
-               append_params = self._dict_to_options(append).split()
-               # Appending kargs, e.g. new kargs by profile or restoring kargs 
replaced by profile
-               for k, val in append.items():
-                       if kargs.get(k):
-                               # If there is karg that we add with new value 
we want to delete it
-                               # and store old value for restoring after 
profile unload
-                               log.debug("adding rpm-ostree kargs %s: %s for 
delete" % (k, kargs[k]))
-                               deleted.setdefault(k, []).extend(kargs[k])
-                               delete_params.extend([k + "=" + v if v is not 
None else k for v in kargs[k]])
-                               kargs[k] = []
-                       kargs.setdefault(k, []).extend(val)
-                       appended[k] = val
-
-               if append_params == delete_params:
-                       log.info("skipping rpm-ostree kargs - append == 
deleting (%s)" % append_params)
-                       return kargs, appended, deleted
-
-               log.info("rpm-ostree kargs - appending: '%s'; deleting: '%s'" % 
(append_params, delete_params))
-               (rc, _, err) = self._cmd.execute(['rpm-ostree', 'kargs'] +
-                                                                               
 ['--append=%s' % v for v in append_params] +
-                                                                               
 ['--delete=%s' % v for v in delete_params], return_err=True)
+       def _modify_rpm_ostree_kargs(self, delete_kargs=[], append_kargs=[]):
+               """
+               Modify (delete and append) kernel arguments in a rpm-ostree 
system.
+               Return a boolean indicating whether the operation was 
successful.
+               """
+               if not self._wait_till_rpm_ostree_idle():
+                       log.error("Error modifying rpm-ostree kargs: rpm-ostree 
is busy")
+                       return False
+               (rc, _, err) = self._cmd.execute(
+                       ["rpm-ostree", "kargs"] +
+                       ["--delete=%s" % karg for karg in delete_kargs] +
+                       ["--append=%s" % karg for karg in append_kargs], 
return_err=True)
                if rc != 0:
-                       log.error("Something went wrong with rpm-ostree 
kargs\n%s" % (err))
-                       return self._options_to_dict(out), None, None
-               else:
-                       return kargs, appended, deleted
+                       log.error("Error modifying rpm-ostree kargs: %s" % err)
+                       return False
+               return True
 
        def _get_effective_options(self, options):
                """Merge provided options with plugin default options and merge 
all cmdline.* options."""
@@ -368,18 +327,16 @@
                        log.info("removing initrd image '%s'" % 
self._initrd_dst_img_val)
                        self._cmd.unlink(self._initrd_dst_img_val)
 
-       def _get_rpm_ostree_changes(self):
+       def _get_appended_rpm_ostree_kargs(self):
+               """Return the list of kernel arguments that were appended by 
this profile (in a rpm-ostree system)."""
                f = self._cmd.read_file(consts.BOOT_CMDLINE_FILE)
                appended = re.search(consts.BOOT_CMDLINE_TUNED_VAR + 
r"=\"(.*)\"", f, flags=re.MULTILINE)
-               appended = appended[1] if appended else ""
-               deleted = re.search(consts.BOOT_CMDLINE_KARGS_DELETED_VAR + 
r"=\"(.*)\"", f, flags=re.MULTILINE)
-               deleted = deleted[1] if deleted else ""
-               return appended, deleted
+               return appended[1].split() if appended else []
 
        def _remove_rpm_ostree_tuning(self):
-               appended, deleted = self._get_rpm_ostree_changes()
-               self._rpm_ostree_kargs(append=self._options_to_dict(deleted), 
delete=self._options_to_dict(appended))
-               self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", 
consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})
+               """Remove kernel parameter tuning in a rpm-ostree system."""
+               
self._modify_rpm_ostree_kargs(delete_kargs=self._get_appended_rpm_ostree_kargs())
+               self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: ""})
 
        def _instance_unapply_static(self, instance, rollback = 
consts.ROLLBACK_SOFT):
                if rollback == consts.ROLLBACK_FULL and not 
self._skip_grub_config_val:
@@ -489,14 +446,30 @@
                return True
 
        def _rpm_ostree_update(self):
-               appended, _ = self._get_rpm_ostree_changes()
-               _cmdline_dict = self._options_to_dict(self._cmdline_val, 
appended)
-               if not _cmdline_dict:
-                       return None
-               (_, _, d) = self._rpm_ostree_kargs(append=_cmdline_dict)
-               if d is None:
+               """Apply kernel parameter tuning in a rpm-ostree system."""
+               appended_kargs = self._get_appended_rpm_ostree_kargs()
+               profile_kargs = self._cmdline_val.split()
+               active_kargs = self._get_rpm_ostree_kargs()
+               if active_kargs is None:
+                       log.error("Not updating kernel arguments, could not 
read the current ones.")
+                       return
+               # Ignore kargs previously appended by TuneD, these will be 
removed later.
+               non_tuned_kargs = active_kargs.split()
+               for karg in appended_kargs:
+                       non_tuned_kargs.remove(karg)
+               # Only append key=value pairs that do not yet appear in kernel 
parameters,
+               # otherwise we would not be able to restore the cmdline to the 
previous state
+               # via rpm-ostree kargs --delete.
+               kargs_to_append = [karg for karg in profile_kargs if karg not 
in non_tuned_kargs]
+               if appended_kargs == kargs_to_append:
+                       # The correct kargs are already set in 
/etc/tuned/bootcmldine,
+                       # we are likely post-reboot and done.
+                       log.info("Kernel arguments already set, not updating.")
                        return
-               self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : 
self._cmdline_val, consts.BOOT_CMDLINE_KARGS_DELETED_VAR : 
self._dict_to_options(d)})
+               # If there are kargs in /etc/bootcmdline and they do not match
+               # the requested ones, there was no rollback, so remove them now.
+               if self._modify_rpm_ostree_kargs(delete_kargs=appended_kargs, 
append_kargs=kargs_to_append):
+                       self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR 
: " ".join(kargs_to_append)})
 
        def _grub2_update(self):
                self._grub2_cfg_patch({consts.GRUB2_TUNED_VAR : 
self._cmdline_val, consts.GRUB2_TUNED_INITRD_VAR : self._initrd_val})
@@ -646,11 +619,10 @@
                v = self._variables.expand(self._cmd.unquote(value))
                if verify:
                        if self._rpm_ostree:
-                               rpm_ostree_kargs = self._rpm_ostree_kargs()[0]
-                               cmdline = 
self._dict_to_options(rpm_ostree_kargs)
+                               cmdline = self._get_rpm_ostree_kargs()
                        else:
                                cmdline = self._cmd.read_file("/proc/cmdline")
-                       if len(cmdline) == 0:
+                       if cmdline is None or len(cmdline) == 0:
                                return None
                        cmdline_set = set(cmdline.split())
                        value_set = set(v.split())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_cpu.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_cpu.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_cpu.py  2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_cpu.py  2025-08-24 
23:48:04.000000000 +0200
@@ -190,7 +190,9 @@
 
        `boost`:::
        The [option]`boost` option allows the CPU to boost above nominal
-       frequencies for shorts periods of time.
+       frequencies for shorts periods of time. On Intel systems with the
+       intel_pstate driver, setting boost=0 will automatically set no_turbo=1
+       to ensure boost is properly disabled.
        +
        .Allowing CPU boost
        ====
@@ -771,17 +773,38 @@
                        log.debug("%s is not online, skipping" % device)
                        return None
                cpu_id = device.lstrip("cpu")
+               boost_set = False
+
                if os.path.exists(self._pstate_boost_path(cpu_id)):
                        if not sim:
                                if boost == "0" or boost == "1":
                                        
self._cmd.write_to_file(self._pstate_boost_path(cpu_id), boost, \
                                                no_error = [errno.ENOENT] if 
remove else False, ignore_same=True)
                                        log.info("Setting boost value '%s' for 
cpu '%s'" % (boost, device))
+                                       boost_set = True
                                else:
                                        log.error("Failed to set boost on cpu 
'%s'. Is the value in the profile correct?" % device)
-                       return str(boost)
                else:
                        log.debug("boost file missing, which can happen on pre 
6.11 kernels.")
+
+               # For Intel systems with intel_pstate driver, handle no_turbo
+               # This ensures boost=0 works properly on Intel CPUs
+               if self._has_intel_pstate and boost in ["0", "1"]:
+                       no_turbo_val = "1" if boost == "0" else "0"
+
+                       if not sim:
+                               try:
+                                       self._set_intel_pstate_attr("no_turbo", 
no_turbo_val)
+                                       log.info("Setting no_turbo to '%s' for 
intel_pstate driver (boost=%s)" % (no_turbo_val, boost))
+                                       boost_set = True
+                               except Exception as e:
+                                       log.warning("Failed to set no_turbo for 
intel_pstate: %s" % str(e))
+
+               if boost_set or sim:
+                       return str(boost)
+               elif boost in ["0", "1"]:
+                       log.warning("Unable to set boost on cpu '%s'. Neither 
per-policy boost nor intel_pstate no_turbo is available." % device)
+
                return None
 
        @command_get("boost")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_disk.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_disk.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_disk.py 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_disk.py 2025-08-24 
23:48:04.000000000 +0200
@@ -134,7 +134,8 @@
                return  device.device_type == "disk" and \
                        device.attributes.get("removable", None) == b"0" and \
                        (device.parent is None or \
-                                       device.parent.subsystem in ["scsi", 
"virtio", "xen", "nvme"])
+                                       device.parent.subsystem in ["scsi", 
"virtio", "xen", "nvme",
+                                                                               
                "mmc"])
 
        def _hardware_events_init(self):
                self._hardware_inventory.subscribe(self, "block", 
self._hardware_events_callback)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_irqbalance.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_irqbalance.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_irqbalance.py   
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_irqbalance.py   
2025-08-24 23:48:04.000000000 +0200
@@ -3,7 +3,6 @@
 from tuned import consts
 import tuned.logs
 import errno
-import perf
 import re
 
 log = tuned.logs.get()
@@ -29,7 +28,7 @@
 
        def __init__(self, *args, **kwargs):
                super(IrqbalancePlugin, self).__init__(*args, **kwargs)
-               self._cpus = perf.cpu_map()
+               self._cpus = self._cmd.get_cpus()
 
        def _instance_init(self, instance):
                instance._has_dynamic_tuning = False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scheduler.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scheduler.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scheduler.py    
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scheduler.py    
2025-08-24 23:48:04.000000000 +0200
@@ -447,6 +447,11 @@
                "latency_ns": "",
        }
 
+       def _disable_perf(self):
+               log.warning("python-perf unavailable, disabling perf support 
and " \
+                       "runtime tuning, you can try to (re)install 
python(3)-perf package")
+               self._perf_available = False
+
        def __init__(self, monitor_repository, storage_factory, 
hardware_inventory, device_matcher, device_matcher_udev, 
plugin_instance_factory, global_cfg, variables):
                super(SchedulerPlugin, self).__init__(monitor_repository, 
storage_factory, hardware_inventory, device_matcher, device_matcher_udev, 
plugin_instance_factory, global_cfg, variables)
                self._has_dynamic_options = True
@@ -465,14 +470,15 @@
                self._ps_blacklist = ""
                self._kthread_process = True
                self._cgroup_ps_blacklist_re = ""
-               # perf is optional, if unavailable, it will be disabled later
+               self._perf_available = True
+
                try:
                        self._cpus = perf.cpu_map()
                except (NameError, AttributeError):
-                       cpus = 
self._cmd.read_file(consts.SYSFS_CPUS_PRESENT_PATH)
+                       self._disable_perf()
                        # it's different type than perf.cpu_map(), but without 
perf we use it as iterable
-                       # which should be compatible, fallback to single core 
CPU if sysfs is unavailable
-                       self._cpus = self._cmd.cpulist_unpack(cpus) if cpus 
else [ 0 ]
+                       # which should be compatible
+                       self._cpus = self._cmd.get_cpus()
 
                self._scheduler_storage_key = self._storage_key(
                                command_name = "scheduler")
@@ -541,7 +547,7 @@
                if self._cmd.get_bool(instance._scheduler.get("runtime", 1)) == 
"0":
                        instance._runtime_tuning = False
                instance._terminate = threading.Event()
-               if self._daemon and instance._runtime_tuning:
+               if self._daemon and instance._runtime_tuning and 
self._perf_available:
                        try:
                                instance._threads = perf.thread_map()
                                evsel = perf.evsel(type = perf.TYPE_SOFTWARE,
@@ -558,9 +564,9 @@
                                        instance._evlist.mmap(pages = 
perf_mmap_pages)
                        # no perf
                        except:
-                               log.warning("python-perf unavailable, disabling 
perf support and " \
-                                       "runtime tuning, you can try to 
(re)install python(3)-perf package")
-                               instance._runtime_tuning = False
+                               self._disable_perf()
+               if not self._perf_available:
+                       instance._runtime_tuning = False
 
        def _instance_cleanup(self, instance):
                if instance._evlist:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scsi_host.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scsi_host.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scsi_host.py    
2025-02-03 20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scsi_host.py    
2025-08-24 23:48:04.000000000 +0200
@@ -14,8 +14,8 @@
        Tunes options for SCSI hosts.
 
        The plug-in sets Aggressive Link Power Management (ALPM) to the value 
specified
-       by the [option]`alpm` option. The option takes one of three values:
-       `min_power`, `medium_power` and `max_performance`.
+       by the [option]`alpm` option. The option takes one of four values:
+       `min_power`, `med_power_with_dipm`, `medium_power` and 
`max_performance`.
 
        NOTE: ALPM is only available on SATA controllers that use the Advanced
        Host Controller Interface (AHCI).
@@ -24,7 +24,7 @@
        ====
        ----
        [scsi_host]
-       alpm=min_power
+       alpm=med_power_with_dipm
        ----
        ====
        """
@@ -83,10 +83,27 @@
        def _get_alpm_policy_file(self, device):
                return os.path.join("/sys/class/scsi_host/", str(device), 
"link_power_management_policy")
 
+       def _get_ahci_port_cmd_file(self, device):
+               return os.path.join("/sys/class/scsi_host/", str(device), 
"ahci_port_cmd")
+
+       def _is_external_sata_port(self, device):
+               port_cmd_file = self._get_ahci_port_cmd_file(device)
+               if not os.path.isfile(port_cmd_file):
+                       return False
+               port_cmd = int(self._cmd.read_file(port_cmd_file), 16)
+               # Bit 18 is HPCP (Hot Plug Capable Port)
+               # Bit 21 is ESP (External SATA Port)
+               return port_cmd & (1 << 18 | 1 << 21) != 0
+
        @command_set("alpm", per_device = True)
        def _set_alpm(self, policy, device, instance, sim, remove):
                if policy is None:
                        return None
+               if self._is_external_sata_port(device):
+                       # According to the SATA AHCI specification, external 
(or hot-plug capable)
+                       # SATA ports must have power management disabled to 
reliably detect hot plug removal.
+                       log.info("Device '%s' is an external SATA controller, 
skipping ALPM setting to support hot plug" % str(device))
+                       return None
                policy_file = self._get_alpm_policy_file(device)
                if not sim:
                        if os.path.exists(policy_file):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_vm.py 
new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_vm.py
--- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_vm.py   2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_vm.py   2025-08-24 
23:48:04.000000000 +0200
@@ -53,7 +53,7 @@
        @staticmethod
        def _check_conflicting_dirty_options(instance, first, second):
                if instance.options[first] is not None and 
instance.options[second] is not None:
-                       log.error("Conflicting options '%s' and '%s', this may 
cause undefined behavior." % (first, second))
+                       log.warning("Conflicting options '%s' and '%s', this 
may cause undefined behavior." % (first, second))
 
        @staticmethod
        def _proc_sys_vm_option_path(option):
@@ -160,18 +160,24 @@
 
        @command_custom("dirty_bytes")
        def _dirty_bytes(self, enabling, value, verify, ignore_missing, 
instance):
+               if value is not None and value.strip().endswith("%"):
+                       return self._dirty_option("dirty_ratio", "dirty_bytes", 
self._check_ratio, enabling, value.strip().rstrip("%"), verify)
                return self._dirty_option("dirty_bytes", "dirty_ratio", 
self._check_twice_pagesize, enabling, value, verify)
 
        @command_custom("dirty_ratio")
        def _dirty_ratio(self, enabling, value, verify, ignore_missing, 
instance):
+               log.warning("The 'dirty_ratio' option is deprecated and does 
not support inheritance, use 'dirty_bytes' with '%' instead.")
                return self._dirty_option("dirty_ratio", "dirty_bytes", 
self._check_ratio, enabling, value, verify)
 
        @command_custom("dirty_background_bytes")
        def _dirty_background_bytes(self, enabling, value, verify, 
ignore_missing, instance):
+               if value is not None and value.strip().endswith("%"):
+                       return self._dirty_option("dirty_background_ratio", 
"dirty_background_bytes", self._check_ratio, enabling, 
value.strip().rstrip("%"), verify)
                return self._dirty_option("dirty_background_bytes", 
"dirty_background_ratio", self._check_positive, enabling, value, verify)
 
        @command_custom("dirty_background_ratio")
        def _dirty_background_ratio(self, enabling, value, verify, 
ignore_missing, instance):
+               log.warning("The 'dirty_background_ratio' option is deprecated 
and does not support inheritance, use 'dirty_background_bytes' with '%' 
instead.")
                return self._dirty_option("dirty_background_ratio", 
"dirty_background_bytes", self._check_ratio, enabling, value, verify)
 
        def _dirty_option(self, option, counterpart, check_fun, enabling, 
value, verify):
@@ -189,6 +195,7 @@
                                int_value = int(value)
                        except ValueError:
                                log.error("The value of '%s' must be an 
integer." % option)
+                               return None
                        if not check_fun(option, int_value):
                                return None
                        if current_value == value:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/config.py 
new/tuned-2.26.0.0+git.181472a/tuned/ppd/config.py
--- old/tuned-2.25.1.0+git.889387b/tuned/ppd/config.py  2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/config.py  2025-08-24 
23:48:04.000000000 +0200
@@ -11,7 +11,7 @@
 BATTERY_SECTION = "battery"
 DEFAULT_PROFILE_OPTION = "default"
 BATTERY_DETECTION_OPTION = "battery_detection"
-THINKPAD_FUNCTION_KEYS_OPTION = "thinkpad_function_keys"
+SYSFS_ACPI_MONITOR_OPTION = "sysfs_acpi_monitor"
 
 
 class ProfileMap:
@@ -75,13 +75,13 @@
         return self._tuned_to_ppd
 
     @property
-    def thinkpad_function_keys(self):
+    def sysfs_acpi_monitor(self):
         """
         Whether to react to changes of ACPI platform profile
         done via function keys (e.g., Fn-L) on newer Thinkpad
         machines. Experimental feature.
         """
-        return self._thinkpad_function_keys
+        return self._sysfs_acpi_monitor
 
     def load_from_file(self, config_file):
         """
@@ -141,4 +141,4 @@
         self._ppd_to_tuned = ProfileMap(profile_dict_ac, profile_dict_dc)
         self._tuned_to_ppd = ProfileMap({v: k for k, v in 
profile_dict_ac.items()}, {v: k for k, v in profile_dict_dc.items()})
 
-        self._thinkpad_function_keys = cfg.getboolean(MAIN_SECTION, 
THINKPAD_FUNCTION_KEYS_OPTION, fallback=False)
+        self._sysfs_acpi_monitor = cfg.getboolean(MAIN_SECTION, 
SYSFS_ACPI_MONITOR_OPTION, fallback=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/controller.py 
new/tuned-2.26.0.0+git.181472a/tuned/ppd/controller.py
--- old/tuned-2.25.1.0+git.889387b/tuned/ppd/controller.py      2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/controller.py      2025-08-24 
23:48:04.000000000 +0200
@@ -229,6 +229,7 @@
         self._watch_manager = pyinotify.WatchManager()
         self._notifier = pyinotify.ThreadedNotifier(self._watch_manager)
         self._inotify_watches = {}
+        self._pinned_virtual_files = []
         self._platform_profile_supported = 
os.path.isfile(PLATFORM_PROFILE_PATH)
         self._no_turbo_supported = os.path.isfile(NO_TURBO_PATH)
         self._lap_mode_supported = os.path.isfile(LAP_MODE_PATH)
@@ -289,19 +290,25 @@
         """
         Sets up inotify file watches.
         """
+        for f in self._pinned_virtual_files:
+            f.close()
+        self._pinned_virtual_files.clear()
         self._watch_manager.rm_watch(list(self._inotify_watches.values()))
         if self._no_turbo_supported:
+            self._pinned_virtual_files.append(open(NO_TURBO_PATH, "r"))
             self._inotify_watches |= 
self._watch_manager.add_watch(path=os.path.dirname(NO_TURBO_PATH),
                                                                    
mask=pyinotify.IN_MODIFY,
-                                                                   
proc_fun=PerformanceDegradedEventHandler(NO_TURBO_PATH, self))
+                                                                   
proc_fun=PerformanceDegradedEventHandler(self, NO_TURBO_PATH))
         if self._lap_mode_supported:
+            self._pinned_virtual_files.append(open(LAP_MODE_PATH, "r"))
             self._inotify_watches |= 
self._watch_manager.add_watch(path=os.path.dirname(LAP_MODE_PATH),
                                                                    
mask=pyinotify.IN_MODIFY,
-                                                                   
proc_fun=PerformanceDegradedEventHandler(LAP_MODE_PATH, self))
-        if self._platform_profile_supported and 
self._config.thinkpad_function_keys:
-           self._inotify_watches |= 
self._watch_manager.add_watch(path=os.path.dirname(PLATFORM_PROFILE_PATH),
-                                                                  
mask=pyinotify.IN_OPEN | pyinotify.IN_MODIFY | pyinotify.IN_CLOSE_WRITE | 
pyinotify.IN_CLOSE_NOWRITE,
-                                                                  
proc_fun=PlatformProfileEventHandler(self))
+                                                                   
proc_fun=PerformanceDegradedEventHandler(self, LAP_MODE_PATH))
+        if self._platform_profile_supported and 
self._config.sysfs_acpi_monitor:
+            self._pinned_virtual_files.append(open(PLATFORM_PROFILE_PATH, "r"))
+            self._inotify_watches |= 
self._watch_manager.add_watch(path=os.path.dirname(PLATFORM_PROFILE_PATH),
+                                                                   
mask=pyinotify.IN_OPEN | pyinotify.IN_MODIFY | pyinotify.IN_CLOSE_WRITE | 
pyinotify.IN_CLOSE_NOWRITE,
+                                                                   
proc_fun=PlatformProfileEventHandler(self))
 
     def check_performance_degraded(self):
         """
@@ -379,6 +386,9 @@
         self._notifier.start()
         while not self._cmd.wait(self._terminate, 1):
             pass
+        for f in self._pinned_virtual_files:
+            f.close()
+        self._pinned_virtual_files.clear()
         self._watch_manager.rm_watch(list(self._inotify_watches.values()))
         self._notifier.stop()
         exports.stop()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/ppd.conf 
new/tuned-2.26.0.0+git.181472a/tuned/ppd/ppd.conf
--- old/tuned-2.25.1.0+git.889387b/tuned/ppd/ppd.conf   2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/ppd.conf   2025-08-24 
23:48:04.000000000 +0200
@@ -2,6 +2,7 @@
 # The default PPD profile
 default=balanced
 battery_detection=true
+sysfs_acpi_monitor=true
 
 [profiles]
 # PPD = TuneD
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/profiles/functions/function_calc_isolated_cores.py
 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/functions/function_calc_isolated_cores.py
--- 
old/tuned-2.25.1.0+git.889387b/tuned/profiles/functions/function_calc_isolated_cores.py
     2025-02-03 20:17:00.000000000 +0100
+++ 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/functions/function_calc_isolated_cores.py
     2025-08-24 23:48:04.000000000 +0200
@@ -3,8 +3,10 @@
 import tuned.logs
 from . import base
 import tuned.consts as consts
+from tuned.utils.commands import commands
 
 log = tuned.logs.get()
+cmd = commands()
 
 class calc_isolated_cores(base.Function):
        """
@@ -46,4 +48,4 @@
                        cpus.sort(key = int)
                        isol_cpus = isol_cpus + cpus[cpus_reserve:]
                isol_cpus.sort(key = int)
-               return ",".join(isol_cpus)
+               return ",".join(cmd.cpulist_pack(isol_cpus))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/loader.py 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/loader.py
--- old/tuned-2.25.1.0+git.889387b/tuned/profiles/loader.py     2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/loader.py     2025-08-24 
23:48:04.000000000 +0200
@@ -51,15 +51,9 @@
                processed_files = []
                self._load_profile(profile_names, profiles, processed_files)
 
-               if len(profiles) > 1:
-                       final_profile = self._profile_merger.merge(profiles)
-               else:
-                       final_profile = profiles[0]
-
+               final_profile = self._profile_merger.merge(profiles)
                final_profile.name = " ".join(profile_names)
-               if "variables" in final_profile.units:
-                       
self._variables.add_from_cfg(final_profile.units["variables"].options)
-                       del(final_profile.units["variables"])
+               self._variables.add_from_cfg(final_profile.variables)
                # FIXME hack, do all variable expansions in one place
                self._expand_vars_in_devices(final_profile)
                self._expand_vars_in_regexes(final_profile)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/merger.py 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/merger.py
--- old/tuned-2.25.1.0+git.889387b/tuned/profiles/merger.py     2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/merger.py     2025-08-24 
23:48:04.000000000 +0200
@@ -1,5 +1,6 @@
-import collections
+import tuned.consts as consts
 from functools import reduce
+from tuned.profiles.profile import Profile
 
 class Merger(object):
        """
@@ -14,7 +15,7 @@
                Merge multiple configurations into one. If there are multiple 
units of the same type, option 'devices'
                is set for each unit with respect to eliminating any duplicate 
devices.
                """
-               merged_config = reduce(self._merge_two, configs)
+               merged_config = reduce(self._merge_two, configs, Profile())
                return merged_config
 
        def _merge_two(self, profile_a, profile_b):
@@ -23,16 +24,29 @@
                from the newer profile. If the 'replace' options of the newer 
unit is 'True', all options from the
                older unit are dropped.
                """
+               if profile_a.name is None:
+                       profile_a.name = profile_b.name
 
                profile_a.options.update(profile_b.options)
 
                for unit_name, unit in list(profile_b.units.items()):
-                       if unit.replace or unit_name not in profile_a.units:
+                       if unit.type == consts.PLUGIN_VARIABLES_UNIT_NAME:
+                               if unit.replace:
+                                       profile_a.variables.clear()
+                               overwritten_variables = 
set(profile_a.variables.keys()) & set(unit.options.keys())
+                               profile_a.variables.update(unit.options)
+                               if unit.prepend:
+                                       for variable in reversed(unit.options):
+                                               if variable not in 
overwritten_variables:
+                                                       
profile_a.variables.move_to_end(variable, last=False)
+                       elif unit.replace or unit_name not in profile_a.units:
                                profile_a.units[unit_name] = unit
                        else:
                                profile_a.units[unit_name].type = unit.type
                                profile_a.units[unit_name].enabled = 
unit.enabled
                                profile_a.units[unit_name].devices = 
unit.devices
+                               if unit.priority is not None:
+                                       profile_a.units[unit_name].priority = 
unit.priority
                                if unit.devices_udev_regex is not None:
                                        
profile_a.units[unit_name].devices_udev_regex = unit.devices_udev_regex
                                if unit.cpuinfo_regex is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/profile.py 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/profile.py
--- old/tuned-2.25.1.0+git.889387b/tuned/profiles/profile.py    2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/profile.py    2025-08-24 
23:48:04.000000000 +0200
@@ -7,10 +7,11 @@
        Representation of a tuning profile.
        """
 
-       __slots__ = ["_name", "_options", "_units"]
+       __slots__ = ["_name", "_options", "_variables", "_units"]
 
-       def __init__(self, name, config):
+       def __init__(self, name=None, config={}):
                self._name = name
+               self._variables = collections.OrderedDict()
                self._init_options(config)
                self._init_units(config)
 
@@ -41,6 +42,10 @@
                self._name = value
 
        @property
+       def variables(self):
+               return self._variables
+
+       @property
        def units(self):
                """
                Units included in the profile.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/unit.py 
new/tuned-2.26.0.0+git.181472a/tuned/profiles/unit.py
--- old/tuned-2.25.1.0+git.889387b/tuned/profiles/unit.py       2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/unit.py       2025-08-24 
23:48:04.000000000 +0200
@@ -6,7 +6,7 @@
        Unit description.
        """
 
-       __slots__ = [ "_name", "_priority", "_type", "_enabled", "_replace", 
"_drop", "_devices", "_devices_udev_regex", \
+       __slots__ = [ "_name", "_priority", "_type", "_enabled", "_replace", 
"_prepend", "_drop", "_devices", "_devices_udev_regex", \
                "_cpuinfo_regex", "_uname_regex", "_script_pre", 
"_script_post", "_options" ]
 
        def __init__(self, name, config):
@@ -15,6 +15,7 @@
                self._type = config.pop("type", self._name)
                self._enabled = config.pop("enabled", True) in [True, "True", 
"true", 1, "1"]
                self._replace = config.pop("replace", False) in [True, "True", 
"true", 1, "1"]
+               self._prepend = config.pop("prepend", False) in [True, "True", 
"true", 1, "1"]
                self._drop = config.pop("drop", None)
                if self._drop is not None:
                        self._drop = re.split(r"\b\s*[,;]\s*", str(self._drop))
@@ -59,6 +60,10 @@
                return self._replace
 
        @property
+       def prepend(self):
+               return self._prepend
+
+       @property
        def drop(self):
                return self._drop
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/units/manager.py 
new/tuned-2.26.0.0+git.181472a/tuned/units/manager.py
--- old/tuned-2.25.1.0+git.889387b/tuned/units/manager.py       2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/units/manager.py       2025-08-24 
23:48:04.000000000 +0200
@@ -89,8 +89,8 @@
                                plugin = 
self._plugins_repository.create(plugin_name)
                                plugins_by_name[plugin_name] = plugin
                                self._plugins.append(plugin)
-                       except 
tuned.plugins.exceptions.NotSupportedPluginException:
-                               log.info("skipping plugin '%s', not supported 
on your system" % plugin_name)
+                       except 
tuned.plugins.exceptions.NotSupportedPluginException as e:
+                               log.info("skipping plugin '%s', not supported 
on your system: %s" % (plugin_name, e))
                                continue
                        except Exception as e:
                                log.error("failed to initialize plugin %s" % 
plugin_name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/utils/commands.py 
new/tuned-2.26.0.0+git.181472a/tuned/utils/commands.py
--- old/tuned-2.25.1.0+git.889387b/tuned/utils/commands.py      2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/utils/commands.py      2025-08-24 
23:48:04.000000000 +0200
@@ -555,3 +555,9 @@
 
        def getconf(self, variable):
                return check_output(["getconf", variable]).decode().strip()
+
+       # Gets list of available CPUs
+       def get_cpus(self):
+               cpus = self.read_file(consts.SYSFS_CPUS_PRESENT_PATH)
+               # fallback to single core CPU if sysfs is unavailable
+               return self.cpulist_unpack(cpus) if cpus else [ 0 ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/tuned-2.25.1.0+git.889387b/tuned/utils/global_config.py 
new/tuned-2.26.0.0+git.181472a/tuned/utils/global_config.py
--- old/tuned-2.25.1.0+git.889387b/tuned/utils/global_config.py 2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/utils/global_config.py 2025-08-24 
23:48:04.000000000 +0200
@@ -75,7 +75,10 @@
                        if isinstance(i, int):
                                return i
                        else:
-                               return int(i, 0)
+                               try:
+                                       return int(i, 0)
+                               except ValueError:
+                                       log.error("Error parsing integer '%s', 
using '%d'." %(str(i), default))
                return default
 
        def get_list(self, key, default = []):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/version.py 
new/tuned-2.26.0.0+git.181472a/tuned/version.py
--- old/tuned-2.25.1.0+git.889387b/tuned/version.py     2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned/version.py     2025-08-24 
23:48:04.000000000 +0200
@@ -1,5 +1,5 @@
 TUNED_VERSION_MAJOR = 2
-TUNED_VERSION_MINOR = 25
-TUNED_VERSION_PATCH = 1
+TUNED_VERSION_MINOR = 26
+TUNED_VERSION_PATCH = 0
 
 TUNED_VERSION_STR = "%d.%d.%d" % (TUNED_VERSION_MAJOR, TUNED_VERSION_MINOR, 
TUNED_VERSION_PATCH)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned-main.conf 
new/tuned-2.26.0.0+git.181472a/tuned-main.conf
--- old/tuned-2.25.1.0+git.889387b/tuned-main.conf      2025-02-03 
20:17:00.000000000 +0100
+++ new/tuned-2.26.0.0+git.181472a/tuned-main.conf      2025-08-24 
23:48:04.000000000 +0200
@@ -77,7 +77,7 @@
 # connections_backlog = 1024
 
 # TuneD daemon rollback strategy. Supported values: auto|not_on_exit
-# - auto: rollbacks are always performed on a profile switch or 
+# - auto: rollbacks are always performed on a profile switch or
 #   graceful TuneD process exit
 # - not_on_exit: rollbacks are always performed on a profile
 #   switch, but not on any kind of TuneD process exit
@@ -87,3 +87,13 @@
 # In case of conflicts in profile names, the later directory
 # takes precedence
 # profile_dirs = /usr/lib/tuned/profiles,/etc/tuned/profiles
+
+# Timeout in seconds to wait until udev settles. Value 0 disables the wait.
+# With non-zero wait TuneD startup is delayed until there are no pending
+# udev events or the specified timeout occurs.
+# The delay can help in situations where there are a lot of udev events
+# during TuneD startup and TuneD is too slow to handle them.
+# In environments where systemd is utilised for starting TuneD
+# it is better to keep this feature disabled and rely on systemd
+# functionality (systemd-udev-settle).
+startup_udev_settle_wait = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned.spec 
new/tuned-2.26.0.0+git.181472a/tuned.spec
--- old/tuned-2.25.1.0+git.889387b/tuned.spec   2025-02-03 20:17:00.000000000 
+0100
+++ new/tuned-2.26.0.0+git.181472a/tuned.spec   2025-08-24 23:48:04.000000000 
+0200
@@ -59,13 +59,14 @@
 
 Summary: A dynamic adaptive system tuning daemon
 Name: tuned
-Version: 2.25.1
+Version: 2.26.0
 Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist}
 License: GPL-2.0-or-later AND CC-BY-SA-3.0
 Source0: 
https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
 URL: http://www.tuned-project.org/
 BuildArch: noarch
-BuildRequires: systemd, desktop-file-utils
+BuildRequires: systemd
+BuildRequires: desktop-file-utils
 %if 0%{?rhel}
 BuildRequires: asciidoc
 %else
@@ -75,7 +76,8 @@
 Requires(preun): systemd
 Requires(postun): systemd
 BuildRequires: make
-BuildRequires: %{_py}, %{_py}-devel
+BuildRequires: %{_py}
+BuildRequires: %{_py}-devel
 # BuildRequires for 'make test'
 # python-mock is needed for python-2.7, but it's not available on RHEL-7, only 
in the EPEL
 %if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 || 0%{?epel})
@@ -91,15 +93,23 @@
 # requires for packages with inconsistent python2/3 names
 %if %{with python3}
 # BuildRequires for 'make test'
-BuildRequires: python3-dbus, python3-gobject-base
-Requires: python3-dbus, python3-gobject-base
+BuildRequires: python3-dbus
+BuildRequires: python3-gobject-base
+Requires: python3-dbus
+Requires: python3-gobject-base
 %else
 # BuildRequires for 'make test'
-BuildRequires: dbus-python, pygobject3-base
-Requires: dbus-python, pygobject3-base
+BuildRequires: dbus-python
+BuildRequires: pygobject3-base
+Requires: dbus-python
+Requires: pygobject3-base
 %endif
-Requires: virt-what, ethtool, gawk
-Requires: util-linux, dbus, polkit
+Requires: virt-what
+Requires: ethtool
+Requires: gawk
+Requires: util-linux
+Requires: dbus
+Requires: polkit
 %if 0%{?fedora} > 22 || 0%{?rhel} > 7
 Recommends: dmidecode
 # https://src.fedoraproject.org/rpms/tuned/pull-request/8
@@ -306,10 +316,8 @@
 make install-ppd DESTDIR="%{buildroot}" BINDIR="%{_bindir}" \
   SBINDIR="%{_sbindir}" DOCDIR="%{docdir}" %{make_python_arg}
 
-%if ! 0%{?rhel}
 # manual
 make install-html DESTDIR=%{buildroot} DOCDIR=%{docdir}
-%endif
 
 # conditional support for grub2, grub2 is not available on all architectures
 # and tuned is noarch package, thus the following hack is needed
@@ -638,6 +646,42 @@
 %config(noreplace) %{_sysconfdir}/tuned/ppd.conf
 
 %changelog
+* Sun Aug 24 2025 Jaroslav Škarvada  <[email protected]> - 2.26.0-1
+- new release
+
+* Sun Aug 17 2025 Jaroslav Škarvada  <[email protected]> - 2.26.0-0.1.rc1
+- new release
+  - tuned-ppd: renamed thinkpad_function_keys as sysfs_acpi_monitor
+  - tuned-ppd: enabled sysfs_acpi_monitor by default
+  - tuned-ppd: fixed inotify watch for performance degradation
+  - tuned-ppd: pinned virtual files in memory for inotify
+  - fixed instance priority inheritance
+    resolves: RHEL-94842
+  - hotplug: added fixes for device remove race condition
+  - tuned-main.conf: added startup_udev_settle_wait option
+    resolves: RHEL-88238
+  - functions: silenced errors if module kvm_intel does not exist
+    resolves: RHEL-79943
+  - functions: make calc_isolated_cores return CPU ranges
+    resolves: RHEL-75751
+  - scsi: used 'med_power_with_dipm' for SATA ALPM
+  - scsi: do not set ALPM on external SATA ports
+    resolves: RHEL-79913
+  - network_latency: Set non-zero rcutree.nohz_full_patience_delay
+    resolves: RHEL-61801
+  - realtime: Disable appropriate P-State drivers
+    resolves: RHEL-85637
+  - plugin_disk: added support for MMC (MultiMediaCard) devices
+  - udev: fix possible traceback in device matcher
+    resolves: RHEL-97087
+  - udev-settle: obey udev buffer size and handle possible tracebacks
+    resolves: RHEL-92637
+  - daemon: re-raise daemon init exception in no-daemon mode
+    resolves: RHEL-71304
+  - vm: deprecate dirty_ratio in favour of dirty_bytes with percents
+    resolves: RHEL-101578
+  - gui: fix the profile deleter script
+
 * Mon Feb  3 2025 Jaroslav Škarvada <[email protected]> - 2.25.1-1
 - new release
   - plugins: added missing instance parameters

++++++ tuned.obsinfo ++++++
--- /var/tmp/diff_new_pack.3m0nyP/_old  2025-09-10 20:22:45.054504689 +0200
+++ /var/tmp/diff_new_pack.3m0nyP/_new  2025-09-10 20:22:45.058504858 +0200
@@ -1,5 +1,5 @@
 name: tuned
-version: 2.25.1.0+git.889387b
-mtime: 1738610220
-commit: 889387b0001b783514523162de21af406e31a549
+version: 2.26.0.0+git.181472a
+mtime: 1756072084
+commit: 181472a0be2125c8cd36c7673ec546d75d396a3d
 

Reply via email to