* [PATCH v2 0/2] alarmtimer: Rework the suspend flow in alarmtimer
@ 2024-02-08 19:56 Pranav Prasad
2024-02-08 19:56 ` [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable Pranav Prasad
2024-02-08 19:56 ` [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier Pranav Prasad
0 siblings, 2 replies; 10+ messages in thread
From: Pranav Prasad @ 2024-02-08 19:56 UTC (permalink / raw)
To: tglx, jstultz, sboyd; +Cc: linux-kernel, krossmo, Pranav Prasad
Hi!
During the driver suspend phase of kernel suspend, alarmtimer's suspend
callback is invoked and it identifies the earliest next wakeup alarm and
programs that into the HW real time clock (RTC). However, there is an
exception to this process. If the next alarm is within the next 2 seconds,
the alarmtimer driver fails to suspend. In this case, a non-trivial amount
of power is spent to freeze and unfreeze all userspace processes and to
suspend and resume a number of devices. In the vast majority of cases, the
imminent alarm that caused the failure was likely already scheduled before
suspend even started. This provides an opportunity to reduce power
consumption if the suspend failure decision is made earlier in the suspend
flow, before the unnecessary extra work is done.
This patch series aims to achieve a kernel suspend flow in which the check
for an imminent alarm is performed early during the suspend prepare phase.
Changes from v1:
- Moved the pm_wakeup_event call to the PM notifier
- Added a check for RTC device in the PM notifier
Pranav Prasad (2):
alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend
check configurable
alarmtimer: Modify alarmtimer suspend callback to check for imminent
alarm using PM notifier
kernel/time/alarmtimer.c | 183 ++++++++++++++++++++++++++++++---------
1 file changed, 143 insertions(+), 40 deletions(-)
--
2.43.0.687.g38aa6559b0-goog
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable 2024-02-08 19:56 [PATCH v2 0/2] alarmtimer: Rework the suspend flow in alarmtimer Pranav Prasad @ 2024-02-08 19:56 ` Pranav Prasad 2024-02-09 20:01 ` John Stultz 2024-02-08 19:56 ` [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier Pranav Prasad 1 sibling, 1 reply; 10+ messages in thread From: Pranav Prasad @ 2024-02-08 19:56 UTC (permalink / raw) To: tglx, jstultz, sboyd; +Cc: linux-kernel, krossmo, Pranav Prasad Currently, the alarmtimer_suspend does not allow the kernel to suspend if the next alarm is within 2 seconds. Create alarmtimer sysfs to make the value of 2 seconds configurable. This allows flexibility to provide a different value based on the type of device running the Linux kernel. As a data point, about 40% of kernel suspend failures in a subset of Android devices were due to this check. A differently configured value can avoid these suspend failures which performs a lot of additional work affecting the power consumption of these Android devices. Signed-off-by: Pranav Prasad <pranavpp@google.com> --- kernel/time/alarmtimer.c | 61 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 4657cb8e8b1f..e4b88c8dc0e1 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -33,6 +33,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 @@ -63,6 +65,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_check_duration_ms = 2 * MSEC_PER_SEC; + +static ssize_t suspend_check_duration_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%lu\n", suspend_check_duration_ms); +} + +static ssize_t suspend_check_duration_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_check_duration_ms = val; + + return n; +} + +static struct kobj_attribute suspend_check_duration = + __ATTR_RW(suspend_check_duration); + +static struct attribute *alarmtimer_attrs[] = { + &suspend_check_duration.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_rtcdev - Return selected rtcdevice * @@ -98,8 +150,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) { @@ -279,8 +334,8 @@ static int alarmtimer_suspend(struct device *dev) if (min == 0) return 0; - if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { - pm_wakeup_event(dev, 2 * MSEC_PER_SEC); + if (ktime_to_ns(min) < suspend_check_duration_ms * NSEC_PER_MSEC) { + pm_wakeup_event(dev, suspend_check_duration_ms); return -EBUSY; } -- 2.43.0.687.g38aa6559b0-goog ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable 2024-02-08 19:56 ` [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable Pranav Prasad @ 2024-02-09 20:01 ` John Stultz 2024-02-13 12:29 ` Thomas Gleixner 0 siblings, 1 reply; 10+ messages in thread From: John Stultz @ 2024-02-09 20:01 UTC (permalink / raw) To: Pranav Prasad; +Cc: tglx, sboyd, linux-kernel, krossmo On Thu, Feb 8, 2024 at 11:56 AM Pranav Prasad <pranavpp@google.com> wrote: > > Currently, the alarmtimer_suspend does not allow the kernel > to suspend if the next alarm is within 2 seconds. > Create alarmtimer sysfs to make the value of 2 seconds configurable. > This allows flexibility to provide a different value based on the > type of device running the Linux kernel. As a data point, about 40% of > kernel suspend failures in a subset of Android devices were due to > this check. A differently configured value can avoid these suspend > failures which performs a lot of additional work affecting the > power consumption of these Android devices. > > Signed-off-by: Pranav Prasad <pranavpp@google.com> I might suggest flipping the order of these two patches, as I'm more wary of UABI changes, so I don't want to hold up the second patch on interface bike shedding. > --- > kernel/time/alarmtimer.c | 61 ++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 58 insertions(+), 3 deletions(-) > > diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c > index 4657cb8e8b1f..e4b88c8dc0e1 100644 > --- a/kernel/time/alarmtimer.c > +++ b/kernel/time/alarmtimer.c > @@ -33,6 +33,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 > @@ -63,6 +65,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_check_duration_ms = 2 * MSEC_PER_SEC; Naming is hard, but "suspend_check_duration" feels particularly opaque for a tunable knob. I can't say I've got a better suggestion off the top of my head, but this might be something worth thinking a bit more on. "imminent_alarm_window" maybe? Though that's not obvious it is connected to suspend, and maybe sounds more urgent than it should. "suspend_alarm_pending_window"? It might also be nice to provide some more details in the commit message about why this should be configurable, and how a user of the interface might choose a proper value to use (including the downsides of going too far in either direction?). thanks -john ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable 2024-02-09 20:01 ` John Stultz @ 2024-02-13 12:29 ` Thomas Gleixner 0 siblings, 0 replies; 10+ messages in thread From: Thomas Gleixner @ 2024-02-13 12:29 UTC (permalink / raw) To: John Stultz, Pranav Prasad; +Cc: sboyd, linux-kernel, krossmo On Fri, Feb 09 2024 at 12:01, John Stultz wrote: > On Thu, Feb 8, 2024 at 11:56 AM Pranav Prasad <pranavpp@google.com> wrote: >> >> Currently, the alarmtimer_suspend does not allow the kernel >> to suspend if the next alarm is within 2 seconds. >> Create alarmtimer sysfs to make the value of 2 seconds configurable. >> This allows flexibility to provide a different value based on the >> type of device running the Linux kernel. As a data point, about 40% of >> kernel suspend failures in a subset of Android devices were due to >> this check. A differently configured value can avoid these suspend >> failures which performs a lot of additional work affecting the >> power consumption of these Android devices. >> >> Signed-off-by: Pranav Prasad <pranavpp@google.com> > > I might suggest flipping the order of these two patches, as I'm more > wary of UABI changes, so I don't want to hold up the second patch on > interface bike shedding. Correct. It's an orthogonal issue and an optimization on top of the early check. Thanks, tglx ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-08 19:56 [PATCH v2 0/2] alarmtimer: Rework the suspend flow in alarmtimer Pranav Prasad 2024-02-08 19:56 ` [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable Pranav Prasad @ 2024-02-08 19:56 ` Pranav Prasad 2024-02-09 19:30 ` John Stultz 2024-02-13 12:28 ` Thomas Gleixner 1 sibling, 2 replies; 10+ messages in thread From: Pranav Prasad @ 2024-02-08 19:56 UTC (permalink / raw) To: tglx, jstultz, sboyd; +Cc: linux-kernel, krossmo, Pranav Prasad The alarmtimer driver currently fails suspend attempts when there is an alarm pending within the next suspend_check_duration_ns nanoseconds, since the system is expected to wake up soon anyway. The entire suspend process is initiated even though the system will immediately awaken. This process includes substantial work before the suspend fails and additional work afterwards to undo the failed suspend that was attempted. Therefore on battery-powered devices that initiate suspend attempts from userspace, it may be advantageous to be able to fail the suspend earlier in the suspend flow to avoid power consumption instead of unnecessarily doing extra work. As one data point, an analysis of a subset of Android devices showed that imminent alarms account for roughly 40% of all suspend failures on average leading to unnecessary power wastage. To facilitate this, register a PM notifier in the alarmtimer subsystem that checks if an alarm is imminent during the prepare stage of kernel suspend denoted by the event PM_SUSPEND_PREPARE. If an alarm is imminent, it returns the errno code ETIME instead of EBUSY to userspace in order to make it easily diagnosable. Signed-off-by: Pranav Prasad <pranavpp@google.com> --- kernel/time/alarmtimer.c | 126 +++++++++++++++++++++++++++------------ 1 file changed, 87 insertions(+), 39 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index e4b88c8dc0e1..809cfd97328d 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -27,6 +27,7 @@ #include <linux/compat.h> #include <linux/module.h> #include <linux/time_namespace.h> +#include <linux/suspend.h> #include "posix-timers.h" @@ -115,6 +116,87 @@ static int alarmtimer_sysfs_add(void) return ret; } +/** + * alarmtimer_get_soonest - Finds the soonest alarm to expire among the + * alarm bases. + * @rtc: ptr to rtc_device struct + * @min: ptr to relative time to the soonest alarm to expire + * @expires: ptr to absolute time of the soonest alarm to expire + * @type: ptr to alarm type + * + * Returns 1 if soonest alarm was found, returns 0 if don't care. + */ +static int alarmtimer_get_soonest(struct rtc_device *rtc, ktime_t *min, + ktime_t *expires, int *type) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&freezer_delta_lock, flags); + *min = freezer_delta; + *expires = freezer_expires; + *type = freezer_alarmtype; + freezer_delta = 0; + spin_unlock_irqrestore(&freezer_delta_lock, flags); + + rtc = alarmtimer_get_rtcdev(); + /* If we have no rtcdev, just return */ + if (!rtc) + return 0; + + /* Find the soonest timer to expire */ + for (i = 0; i < ALARM_NUMTYPE; i++) { + struct alarm_base *base = &alarm_bases[i]; + struct timerqueue_node *next; + ktime_t delta; + + spin_lock_irqsave(&base->lock, flags); + next = timerqueue_getnext(&base->timerqueue); + spin_unlock_irqrestore(&base->lock, flags); + if (!next) + continue; + delta = ktime_sub(next->expires, base->get_ktime()); + if (!*min || delta < *min) { + *expires = next->expires; + *min = delta; + *type = i; + } + } + + if (*min == 0) + return 0; + + return 1; +} + +static int alarmtimer_pm_callback(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + ktime_t min, expires; + struct rtc_device *rtc = NULL; + int type; + + switch (mode) { + case PM_SUSPEND_PREPARE: + /* Find the soonest timer to expire */ + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) + return NOTIFY_DONE; + + if (ktime_to_ns(min) < + suspend_check_duration_ms * NSEC_PER_MSEC) { + pr_warn("[%s] Suspend abort due to imminent alarm\n", __func__); + pm_wakeup_event(&rtc->dev, suspend_check_duration_ms); + return notifier_from_errno(-ETIME); + } + } + + return NOTIFY_DONE; +} + +static struct notifier_block alarmtimer_pm_notifier = { + .notifier_call = alarmtimer_pm_callback, +}; + /** * alarmtimer_get_rtcdev - Return selected rtcdevice * @@ -181,6 +263,7 @@ static int alarmtimer_rtc_add_device(struct device *dev) static inline void alarmtimer_rtc_timer_init(void) { rtc_timer_init(&rtctimer, NULL, NULL); + register_pm_notifier(&alarmtimer_pm_notifier); } static struct class_interface alarmtimer_rtc_interface = { @@ -296,49 +379,14 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining); static int alarmtimer_suspend(struct device *dev) { ktime_t min, now, expires; - int i, ret, type; - struct rtc_device *rtc; - unsigned long flags; + struct rtc_device *rtc = NULL; struct rtc_time tm; + int ret, type; - spin_lock_irqsave(&freezer_delta_lock, flags); - min = freezer_delta; - expires = freezer_expires; - type = freezer_alarmtype; - freezer_delta = 0; - spin_unlock_irqrestore(&freezer_delta_lock, flags); - - rtc = alarmtimer_get_rtcdev(); - /* If we have no rtcdev, just return */ - if (!rtc) - return 0; - - /* Find the soonest timer to expire*/ - for (i = 0; i < ALARM_NUMTYPE; i++) { - struct alarm_base *base = &alarm_bases[i]; - struct timerqueue_node *next; - ktime_t delta; - - spin_lock_irqsave(&base->lock, flags); - next = timerqueue_getnext(&base->timerqueue); - spin_unlock_irqrestore(&base->lock, flags); - if (!next) - continue; - delta = ktime_sub(next->expires, base->get_ktime()); - if (!min || (delta < min)) { - expires = next->expires; - min = delta; - type = i; - } - } - if (min == 0) + /* Find the soonest timer to expire */ + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) return 0; - if (ktime_to_ns(min) < suspend_check_duration_ms * NSEC_PER_MSEC) { - pm_wakeup_event(dev, suspend_check_duration_ms); - return -EBUSY; - } - trace_alarmtimer_suspend(expires, type); /* Setup an rtc timer to fire that far in the future */ -- 2.43.0.687.g38aa6559b0-goog ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-08 19:56 ` [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier Pranav Prasad @ 2024-02-09 19:30 ` John Stultz 2024-02-13 12:28 ` Thomas Gleixner 1 sibling, 0 replies; 10+ messages in thread From: John Stultz @ 2024-02-09 19:30 UTC (permalink / raw) To: Pranav Prasad; +Cc: tglx, sboyd, linux-kernel, krossmo On Thu, Feb 8, 2024 at 11:56 AM Pranav Prasad <pranavpp@google.com> wrote: > > The alarmtimer driver currently fails suspend attempts when there is an > alarm pending within the next suspend_check_duration_ns nanoseconds, since > the system is expected to wake up soon anyway. The entire suspend process > is initiated even though the system will immediately awaken. This process > includes substantial work before the suspend fails and additional work > afterwards to undo the failed suspend that was attempted. Therefore on > battery-powered devices that initiate suspend attempts from userspace, it > may be advantageous to be able to fail the suspend earlier in the suspend > flow to avoid power consumption instead of unnecessarily doing extra work. > As one data point, an analysis of a subset of Android devices showed that > imminent alarms account for roughly 40% of all suspend failures on average > leading to unnecessary power wastage. > > To facilitate this, register a PM notifier in the alarmtimer subsystem > that checks if an alarm is imminent during the prepare stage of kernel > suspend denoted by the event PM_SUSPEND_PREPARE. If an alarm is imminent, > it returns the errno code ETIME instead of EBUSY to userspace in order to > make it easily diagnosable. Thanks for continuing to iterate on this! One concern below... > +static int alarmtimer_pm_callback(struct notifier_block *nb, > + unsigned long mode, void *_unused) > +{ > + ktime_t min, expires; > + struct rtc_device *rtc = NULL; > + int type; > + > + switch (mode) { > + case PM_SUSPEND_PREPARE: > + /* Find the soonest timer to expire */ > + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) > + return NOTIFY_DONE; > + > + if (ktime_to_ns(min) < > + suspend_check_duration_ms * NSEC_PER_MSEC) { > + pr_warn("[%s] Suspend abort due to imminent alarm\n", __func__); > + pm_wakeup_event(&rtc->dev, suspend_check_duration_ms); > + return notifier_from_errno(-ETIME); > + } > + } > + > + return NOTIFY_DONE; > +} > + So the alarmtimer_pm_callback provides an earlier warning that we have an imminent alarm, looks ok to me. > @@ -296,49 +379,14 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining); > static int alarmtimer_suspend(struct device *dev) > { ... > + /* Find the soonest timer to expire */ > + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) > return 0; > > - if (ktime_to_ns(min) < suspend_check_duration_ms * NSEC_PER_MSEC) { > - pm_wakeup_event(dev, suspend_check_duration_ms); > - return -EBUSY; > - } It seems like we'd want to preserve the check in alarmtimer_suspend() as well, no? As the various suspend calls might take awhile and in that time, the next timer may have slipped into the window of being imminent. thanks -john ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-08 19:56 ` [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier Pranav Prasad 2024-02-09 19:30 ` John Stultz @ 2024-02-13 12:28 ` Thomas Gleixner 2024-02-13 20:30 ` Pranav Prasad 1 sibling, 1 reply; 10+ messages in thread From: Thomas Gleixner @ 2024-02-13 12:28 UTC (permalink / raw) To: Pranav Prasad, jstultz, sboyd; +Cc: linux-kernel, krossmo, Pranav Prasad On Thu, Feb 08 2024 at 19:56, Pranav Prasad wrote: The subject line wants some trimming. It's supposed to be a concise short summary and not a novel. Aside of that it's blantantly wrong. It does not modify the suspend callback to check with a PM notifier. It adds a PM notifier to check early before the suspend callback runs. > +/** > + * alarmtimer_get_soonest - Finds the soonest alarm to expire among the > + * alarm bases. > + * @rtc: ptr to rtc_device struct > + * @min: ptr to relative time to the soonest alarm to expire > + * @expires: ptr to absolute time of the soonest alarm to expire > + * @type: ptr to alarm type > + * > + * Returns 1 if soonest alarm was found, returns 0 if don't care. > + */ > +static int alarmtimer_get_soonest(struct rtc_device *rtc, ktime_t *min, > + ktime_t *expires, int *type) Please align the second argument with the first argument of the function. Also the return value wants to be bool. > +{ > + int i; > + unsigned long flags; Please see: https://www.kernel.org/doc/html/latest/process/maintainer-tip.html#variable-declarations > + spin_lock_irqsave(&freezer_delta_lock, flags); > + *min = freezer_delta; > + *expires = freezer_expires; > + *type = freezer_alarmtype; > + freezer_delta = 0; > + spin_unlock_irqrestore(&freezer_delta_lock, flags); This only makes sense for the actual suspend operation because freezing of processes happens after the notifier callback runs. > + rtc = alarmtimer_get_rtcdev(); > + /* If we have no rtcdev, just return */ > + if (!rtc) > + return 0; > + > + /* Find the soonest timer to expire */ > + for (i = 0; i < ALARM_NUMTYPE; i++) { > + struct alarm_base *base = &alarm_bases[i]; > + struct timerqueue_node *next; > + ktime_t delta; > + > + spin_lock_irqsave(&base->lock, flags); > + next = timerqueue_getnext(&base->timerqueue); > + spin_unlock_irqrestore(&base->lock, flags); > + if (!next) > + continue; > + delta = ktime_sub(next->expires, base->get_ktime()); > + if (!*min || delta < *min) { You can spare the !*min if you initialize min to KTIME_MAX. > + *expires = next->expires; > + *min = delta; > + *type = i; > + } > + } > + > + if (*min == 0) !*min above and *min == 0 here. Can we have consistency please? > + return 0; > + > + return 1; > +} > + > +static int alarmtimer_pm_callback(struct notifier_block *nb, > + unsigned long mode, void *_unused) > +{ > + ktime_t min, expires; > + struct rtc_device *rtc = NULL; > + int type; Same as above vs. ordering. > + switch (mode) { > + case PM_SUSPEND_PREPARE: > + /* Find the soonest timer to expire */ > + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) > + return NOTIFY_DONE; > + > + if (ktime_to_ns(min) < > + suspend_check_duration_ms * NSEC_PER_MSEC) { No need for the line break. 80 character limit is gone. > + pr_warn("[%s] Suspend abort due to imminent alarm\n", __func__); Why is this a warning? If at all it wants to be pr_debug() and the __func_ is pretty useless as grep is able to find the string, no? > + pm_wakeup_event(&rtc->dev, suspend_check_duration_ms); How is this supposed to work? rtc is NULL. > + return notifier_from_errno(-ETIME); > + } > + } > + > + return NOTIFY_DONE; > +} > + > +static struct notifier_block alarmtimer_pm_notifier = { > + .notifier_call = alarmtimer_pm_callback, > +}; > + > /** > * alarmtimer_get_rtcdev - Return selected rtcdevice > * > @@ -181,6 +263,7 @@ static int alarmtimer_rtc_add_device(struct device *dev) > static inline void alarmtimer_rtc_timer_init(void) > { > rtc_timer_init(&rtctimer, NULL, NULL); > + register_pm_notifier(&alarmtimer_pm_notifier); > } > > static struct class_interface alarmtimer_rtc_interface = { > @@ -296,49 +379,14 @@ EXPORT_SYMBOL_GPL(alarm_expires_remaining); > static int alarmtimer_suspend(struct device *dev) > { > ktime_t min, now, expires; > - int i, ret, type; > - struct rtc_device *rtc; > - unsigned long flags; > + struct rtc_device *rtc = NULL; > struct rtc_time tm; > + int ret, type; See above. SNIP > /* Setup an rtc timer to fire that far in the future */ And another NULL pointer dereference follows suit. How was this ever tested? You need: rtc = alarmtimer_get_rtcdev(); if (!rtc) return [0|NOTIFY_DONE]; in both functions and then hand in rtc to alarmtimer_get_soonest(), no? Thanks, tglx ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-13 12:28 ` Thomas Gleixner @ 2024-02-13 20:30 ` Pranav Prasad 2024-02-13 22:38 ` Thomas Gleixner 0 siblings, 1 reply; 10+ messages in thread From: Pranav Prasad @ 2024-02-13 20:30 UTC (permalink / raw) To: tglx, jstultz, sboyd; +Cc: linux-kernel, krossmo > Why is this a warning? If at all it wants to be pr_debug() and the > __func_ is pretty useless as grep is able to find the string, no? Agreed with the pr_debug(), doesn't need to be a warning. I had made it a warning so that it is logged by default (KERN_WARN), so that it can grepped for without enabling dynamic debug for this module. > How is this supposed to work? rtc is NULL. alarmtimer_get_soonest() has the following: rtc = alarmtimer_get_rtcdev(); if (!rtc) return 0; rtc is set in alarmtimer_get_soonest(). If rtc is NULL, the notifier returns NOTIFY_DONE before even reaching pm_wakeup_event(), hence there is no NULL pointer dereference expected. I agree that I should move it out of alarmtimer_get_soonest() and assign it before the function call as it is unrelated to getting the soonest alarm. > How was this ever tested? I tested it by forcing kernel suspend writing 'mem' to /sys/power/state and using a large window (120s instead of the current 2s) so that a pending alarm is likely. The debug print is logged as expected without any kernel crash, and the suspend gets aborted. Thanks for the other comments, Thomas and John! I shall send out a v3 with all the fixes. Regards, Pranav ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-13 20:30 ` Pranav Prasad @ 2024-02-13 22:38 ` Thomas Gleixner 2024-02-14 1:03 ` Pranav Prasad 0 siblings, 1 reply; 10+ messages in thread From: Thomas Gleixner @ 2024-02-13 22:38 UTC (permalink / raw) To: Pranav Prasad, jstultz, sboyd; +Cc: linux-kernel, krossmo Pranav! On Tue, Feb 13 2024 at 20:30, Pranav Prasad wrote: >> How is this supposed to work? rtc is NULL. > > alarmtimer_get_soonest() has the following: > rtc = alarmtimer_get_rtcdev(); > if (!rtc) > return 0; > > rtc is set in alarmtimer_get_soonest(). If rtc is NULL, the notifier > returns NOTIFY_DONE before even reaching pm_wakeup_event(), hence there is > no NULL pointer dereference expected. struct rtc_device *rtc = NULL; if (!alarmtimer_get_soonest(rtc, ....) return 0 ; pm_wakeup_event(rtc->dev); static bool alarmtimer_get_soonest(struct rtc_device *rtc, ....) { rtc = alarmtimer_get_rtcdev(); if (!rtc) return false; ... return true; } How is the assignment in alarmtimer_get_soonest() causing 'rtc' at the callsite to become magically non NULL unless you have this shiny new AI enhanced compiler with the long awaited 'do what I mean' optimization enabled by default. My old school brain based compiler is absolutely sure that both places which I pointed out are straight forward unconditional NULL pointer dereferences. See below. >> How was this ever tested? > > I tested it by forcing kernel suspend writing 'mem' to /sys/power/state and > using a large window (120s instead of the current 2s) so that a pending > alarm is likely. The debug print is logged as expected without any kernel > crash, and the suspend gets aborted. I have no idea what you tested, but definitely not the complete submitted code. The only reason why this did not explode in your face in pm_wakeup_event() is that this function has a NULL pointer check and struct rtc_device has @dev as first member, which means that rtc == &rtc->dev resulting in the NULL pointer check to be effective because &rtc->dev evaluates to NULL. But that does not make the code more correct. It's still am unconditional NULL pointer dereference by definition, no? Just flip the ordering of @dev in @owner in struct rtc_device and watch the show. alarmtimer_suspend() did not explode in your face because either the notifier aborted suspend, which means the function was never reached, or there was no timer armed. Why? Because rtc_cancel_timer() has no NULL pointer check and unconditionally dereferences @rtc. Just for the record. I missed to spot this gem in your patch: > + /* Find the soonest timer to expire */ > + if (!alarmtimer_get_soonest(rtc, &min, &expires, &type)) > return 0; > > - if (ktime_to_ns(min) < suspend_check_duration_ms * NSEC_PER_MSEC) { > - pm_wakeup_event(dev, suspend_check_duration_ms); > - return -EBUSY; > - } > - So you delete the threshold check. What makes sure that a timer which got armed _after_ the notifier ran or one of the nanosleep timers which are only accounted for after freezing are checked for expiring before the threshold? Nothing, right? But sure, the patch did what you wanted to demonstrate and that's why it is correct and perfect, right? I conceed that your patch works perfectly correct under the following condition: Either alarmtimer_pm_callback() aborts the suspend or alarmtimer_get_soonest() does not find an armed timer when called in alarmtimer_suspend() Unfortunately that's not reflecting reality in production systems unless I'm missing something important here. Thanks, tglx ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier 2024-02-13 22:38 ` Thomas Gleixner @ 2024-02-14 1:03 ` Pranav Prasad 0 siblings, 0 replies; 10+ messages in thread From: Pranav Prasad @ 2024-02-14 1:03 UTC (permalink / raw) To: tglx, jstultz, sboyd; +Cc: linux-kernel, krossmo Thanks Thomas for the detailed review. I understand that I got a false positive, and I shall make the suggested changes for v3. Regards, Pranav ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-02-14 1:03 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-02-08 19:56 [PATCH v2 0/2] alarmtimer: Rework the suspend flow in alarmtimer Pranav Prasad 2024-02-08 19:56 ` [PATCH v2 1/2] alarmtimer: Create alarmtimer sysfs to make duration of kernel suspend check configurable Pranav Prasad 2024-02-09 20:01 ` John Stultz 2024-02-13 12:29 ` Thomas Gleixner 2024-02-08 19:56 ` [PATCH v2 2/2] alarmtimer: Modify alarmtimer suspend callback to check for imminent alarm using PM notifier Pranav Prasad 2024-02-09 19:30 ` John Stultz 2024-02-13 12:28 ` Thomas Gleixner 2024-02-13 20:30 ` Pranav Prasad 2024-02-13 22:38 ` Thomas Gleixner 2024-02-14 1:03 ` Pranav Prasad
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox