diff --git a/com.redhat.tuned.policy b/com.redhat.tuned.policy
index 8bee088b8..cc41fd3ed 100644
--- a/com.redhat.tuned.policy
+++ b/com.redhat.tuned.policy
@@ -177,6 +177,16 @@
+
+ Dump TuneD profile
+ Authentication is required to dump TuneD profile
+
+ yes
+ yes
+ yes
+
+
+
Verify TuneD profile, ignore missing values
Authentication is required to verify TuneD profile
diff --git a/tuned-adm.py b/tuned-adm.py
index 83ed56984..835640969 100755
--- a/tuned-adm.py
+++ b/tuned-adm.py
@@ -91,6 +91,9 @@ def check_log_level(value):
parser_verify.set_defaults(action="verify_profile")
parser_verify.add_argument("--ignore-missing", "-i", action="store_true", help="do not treat missing/non-supported tunings as errors")
+ parser_dump = subparsers.add_parser("dump", help="dump current profile")
+ parser_dump.set_defaults(action="dump")
+
parser_auto_profile = subparsers.add_parser("auto_profile", help="enable automatic profile selection mode, switch to the recommended profile")
parser_auto_profile.set_defaults(action="auto_profile")
diff --git a/tuned/admin/admin.py b/tuned/admin/admin.py
index 8f8682f39..932ed1dd0 100644
--- a/tuned/admin/admin.py
+++ b/tuned/admin/admin.py
@@ -375,6 +375,18 @@ def _action_verify_profile(self, ignore_missing):
print("Not supported in no_daemon mode.")
return False
+ def _action_dbus_dump(self):
+ (ret, msg) = self._controller.dump()
+ if ret:
+ print(msg)
+ else:
+ self._error("Unable to dump profile: '%s'" % msg)
+ return self._controller.exit(ret)
+
+ def _action_dump(self):
+ print("Not supported in no_daemon mode.")
+ return False
+
def _action_dbus_off(self):
# 25 seconds default DBus timeout + 5 secs safety margin
timeout = 25 + 5
diff --git a/tuned/admin/dbus_controller.py b/tuned/admin/dbus_controller.py
index 22c8b8d3b..273c66f2e 100644
--- a/tuned/admin/dbus_controller.py
+++ b/tuned/admin/dbus_controller.py
@@ -134,6 +134,9 @@ def recommend_profile(self):
def verify_profile(self):
return self._call("verify_profile")
+ def dump(self):
+ return self._call("dump_profile")
+
def verify_profile_ignore_missing(self):
return self._call("verify_profile_ignore_missing")
diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py
index 6a59a1d86..b43810989 100644
--- a/tuned/daemon/controller.py
+++ b/tuned/daemon/controller.py
@@ -279,6 +279,12 @@ def verify_profile_ignore_missing(self, caller = None):
return False
return self._daemon.verify_profile(ignore_missing = True)
+ @exports.export("", "(bs)")
+ def dump_profile(self, caller = None):
+ if caller == "":
+ return False
+ return self._daemon.dump_profile()
+
@exports.export("", "a{sa{ss}}")
def get_all_plugins(self, caller = None):
"""Return dictionary with accesible plugins
diff --git a/tuned/daemon/daemon.py b/tuned/daemon/daemon.py
index 81582d05d..cc3e2a23b 100644
--- a/tuned/daemon/daemon.py
+++ b/tuned/daemon/daemon.py
@@ -360,6 +360,30 @@ def verify_profile(self, ignore_missing):
self._not_used.set()
return ret
+ def dump_profile(self):
+ if not self.is_running():
+ s = "TuneD is not running"
+ log.error(s)
+ return (False, s)
+
+ if self._profile is None:
+ s = "no profile is set"
+ log.error(s)
+ return (False, s)
+
+ if not self._profile_applied.is_set():
+ s = "profile is not applied"
+ log.error(s)
+ return (False, s)
+
+ # using daemon, the main loop mustn't exit before our completion
+ self._not_used.clear()
+ log.info("dumping profile(s): %s" % self._profile.name)
+ s = self._unit_manager.dump_tuning()
+ # main loop is allowed to exit
+ self._not_used.set()
+ return (True, s)
+
# profile_switch is helper telling plugins whether the stop is due to profile switch
def stop(self, profile_switch = False):
if not self.is_running():
diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py
index 8eaf48ada..539bc2d8d 100644
--- a/tuned/plugins/base.py
+++ b/tuned/plugins/base.py
@@ -290,6 +290,27 @@ def instance_verify_tuning(self, instance, ignore_missing):
else:
return None
+ def instance_dump_tuning(self, instance):
+ """
+ Dump tuning if the plugin instance is active.
+ """
+ if not instance.active:
+ return ""
+
+ s = "[%s]\n" % instance.name
+ s += "type = %s\n" % self.name
+ if instance._devices_expression:
+ s += "devices = %s\n" % instance._devices_expression
+ if instance._devices_udev_regex:
+ s += "devices_udev_regex = %s\n" % instance._devices_udev_regex
+ if instance._script_pre:
+ s += "script_pre = %s\n" % instance._script_pre
+ if instance._script_post:
+ s += "script_post = %s\n" % instance._script_post
+ for option, val in instance._options.items():
+ s += "%s = %s\n" % (option, val)
+ return s
+
def instance_update_tuning(self, instance):
"""
Apply dynamic tuning if the plugin instance is active.
diff --git a/tuned/plugins/instance/instance.py b/tuned/plugins/instance/instance.py
index 1e286729d..65f1722f8 100644
--- a/tuned/plugins/instance/instance.py
+++ b/tuned/plugins/instance/instance.py
@@ -82,6 +82,9 @@ def apply_tuning(self):
def verify_tuning(self, ignore_missing):
return self._plugin.instance_verify_tuning(self, ignore_missing)
+ def dump_tuning(self):
+ return self._plugin.instance_dump_tuning(self)
+
def update_tuning(self):
self._plugin.instance_update_tuning(self)
diff --git a/tuned/units/manager.py b/tuned/units/manager.py
index 2612c1c4e..6225f509c 100644
--- a/tuned/units/manager.py
+++ b/tuned/units/manager.py
@@ -156,6 +156,13 @@ def verify_tuning(self, ignore_missing):
ret = False
return ret
+ def dump_tuning(self):
+ s = ""
+ for instance in self._instances:
+ s += self._try_call("dump_tuning", None,
+ instance.dump_tuning) + "\n"
+ return s[:-1]
+
def update_tuning(self):
for instance in self._instances:
self._try_call("update_tuning", None,