lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240214092902.1908443-3-pranavpp@google.com>
Date: Wed, 14 Feb 2024 09:29:02 +0000
From: Pranav Prasad <pranavpp@...gle.com>
To: tglx@...utronix.de, jstultz@...gle.com, sboyd@...nel.org
Cc: linux-kernel@...r.kernel.org, krossmo@...gle.com, 
	Pranav Prasad <pranavpp@...gle.com>
Subject: [PATCH v3 2/2] alarmtimer: Create sysfs to make alarm check window configurable

Currently, the alarmtimer_suspend does not allow the kernel
to suspend if the next alarm is within 2 seconds. Instead, a configurable
value for the window to check the next pending alarm allows developers
to change the value according to their specific device and use case.
As an example, on Android devices if the value is changed to the short
suspend threshold used in Android's SuspendControlService, it is expected
to lower power consumption during kernel suspend.

The value to be configured needs to be found experimentally based on the
device and use case. The current value of 2 seconds will continue to be
used as the default if no changes are made. If the value is configured to
be very small, there may be a pending alarm that would wake the system up
right after the successful kernel suspend, which would devalue the
benefits of having the check. If the value is configured to be very large,
the kernel suspend would be aborted regularly which would cause to lose
the benefits of kernel suspension in general. Therefore, the value
should not lean too much in either direction.

To facilitate this, create alarmtimer sysfs to make the value of
2 seconds configurable.

Signed-off-by: Pranav Prasad <pranavpp@...gle.com>
---
 kernel/time/alarmtimer.c | 70 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 64 insertions(+), 6 deletions(-)

diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 366ca3568f87..d11f8cb945c2 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -34,6 +34,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/alarmtimer.h>
 
+static const char alarmtimer_group_name[] = "alarmtimer";
+
 /**
  * struct alarm_base - Alarm timer bases
  * @lock:		Lock for syncrhonized access to the base
@@ -64,6 +66,56 @@ static struct rtc_timer		rtctimer;
 static struct rtc_device	*rtcdev;
 static DEFINE_SPINLOCK(rtcdev_lock);
 
+/* Duration to check for soonest alarm during kernel suspend */
+static unsigned long suspend_alarm_pending_window_ms = 2 * MSEC_PER_SEC;
+
+static ssize_t suspend_alarm_pending_window_show(struct kobject *kobj,
+					struct kobj_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%lu\n", suspend_alarm_pending_window_ms);
+}
+
+static ssize_t suspend_alarm_pending_window_store(struct kobject *kobj,
+			struct kobj_attribute *attr, const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (kstrtoul(buf, 10, &val))
+		return -EINVAL;
+
+	suspend_alarm_pending_window_ms = val;
+
+	return n;
+}
+
+static struct kobj_attribute suspend_alarm_pending_window =
+			__ATTR_RW(suspend_alarm_pending_window);
+
+static struct attribute *alarmtimer_attrs[] = {
+	&suspend_alarm_pending_window.attr,
+	NULL,
+};
+
+static const struct attribute_group alarmtimer_attr_group = {
+	.name   = alarmtimer_group_name,
+	.attrs  = alarmtimer_attrs,
+};
+
+/**
+ * alarmtimer_sysfs_add - Adds sysfs attributes for alarmtimer
+ *
+ * Returns 0 if successful, non-zero value for error.
+ */
+static int alarmtimer_sysfs_add(void)
+{
+	int ret = sysfs_create_group(kernel_kobj, &alarmtimer_attr_group);
+
+	if (ret)
+		pr_warn("[%s] failed to create a sysfs group\n", __func__);
+
+	return ret;
+}
+
 /**
  * alarmtimer_get_soonest - Finds the soonest alarm to expire among the
  * alarm bases.
@@ -105,7 +157,7 @@ static bool alarmtimer_get_soonest(ktime_t *min,
 }
 
 static int alarmtimer_pm_callback(struct notifier_block *nb,
-			    	  unsigned long mode, void *_unused)
+				  unsigned long mode, void *_unused)
 {
 	struct rtc_device *rtc;
 	ktime_t min, expires;
@@ -122,9 +174,11 @@ static int alarmtimer_pm_callback(struct notifier_block *nb,
 		if (!alarmtimer_get_soonest(&min, &expires, &type))
 			return NOTIFY_DONE;
 
-		if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+		if (ktime_to_ns(min) <
+		    suspend_alarm_pending_window_ms * NSEC_PER_MSEC) {
 			pr_debug("Suspend abort due to imminent alarm\n");
-			pm_wakeup_event(&rtc->dev, 2 * MSEC_PER_SEC);
+			pm_wakeup_event(&rtc->dev,
+					suspend_alarm_pending_window_ms);
 			return notifier_from_errno(-ETIME);
 		}
 	}
@@ -171,8 +225,11 @@ static int alarmtimer_rtc_add_device(struct device *dev)
 
 	pdev = platform_device_register_data(dev, "alarmtimer",
 					     PLATFORM_DEVID_AUTO, NULL, 0);
-	if (!IS_ERR(pdev))
+	if (!IS_ERR(pdev)) {
 		device_init_wakeup(&pdev->dev, true);
+		if (alarmtimer_sysfs_add())
+			pr_warn("[%s] Failed to add alarmtimer sysfs attributes\n", __func__);
+	}
 
 	spin_lock_irqsave(&rtcdev_lock, flags);
 	if (!IS_ERR(pdev) && !rtcdev) {
@@ -336,9 +393,10 @@ static int alarmtimer_suspend(struct device *dev)
 	if (!alarmtimer_get_soonest(&min, &expires, &type))
 		return 0;
 
-	if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+	if (ktime_to_ns(min) <
+	    suspend_alarm_pending_window_ms * NSEC_PER_MSEC) {
 		pr_debug("Suspend abort due to imminent alarm\n");
-		pm_wakeup_event(dev, 2 * MSEC_PER_SEC);
+		pm_wakeup_event(dev, suspend_alarm_pending_window_ms);
 		return -ETIME;
 	}
 
-- 
2.43.0.687.g38aa6559b0-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ