Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0e36a9a4a788e4e92407774df76c545910810d35
Commit:     0e36a9a4a788e4e92407774df76c545910810d35
Parent:     bf4994d781c69cc15844d63122320e46ddde6464
Author:     Mark Lord <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 01:28:21 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Oct 16 09:43:13 2007 -0700

    rtc: fix readback from /sys/class/rtc/rtc?/wakealarm
    
    Fix readback of RTC alarms on platforms which return -1 in
    non-hardware-supported RTC alarm fields.
    
    To fill in the missing (-1) values, we grab an RTC timestamp along with the
    RTC alarm value, and use the timestamp fields to populate the missing alarm
    fields.
    
    To counter field-wrap races (since the timestamp and alarm are not read
    together atomically), we read the RTC timestamp both before and after
    reading the RTC alarm value, and then check for wrapped fields --> if any
    have wrapped, we know we have a possible inconsistency, so we loop and
    reread the timestamp and alarm again.
    
    Wrapped fields in the RTC timestamps are an issue because rtc-cmos.c, for
    example, also gets/uses an RTC timestamp internally while fetching the RTC
    alarm.  If our timestamp here wasn't the same (minutes and higher) as what
    was used internally there, then we might end up populating the -1 fields
    with inconsistent values.
    
    This fixes readbacks from /sys/class/rtc/rtc?/wakealarm, as well as other
    code paths which call rtc_read_alarm().
    
    Signed-off-by: Mark Lord <[EMAIL PROTECTED]>
    Cc: David Brownell <[EMAIL PROTECTED]>
    Cc: Alessandro Zummo <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/rtc/interface.c |   83 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 1 deletions(-)

diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 8adcab3..de0da54 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -100,7 +100,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
 }
 EXPORT_SYMBOL_GPL(rtc_set_mmss);
 
-int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm 
*alarm)
 {
        int err;
 
@@ -120,6 +120,87 @@ int rtc_read_alarm(struct rtc_device *rtc, struct 
rtc_wkalrm *alarm)
        mutex_unlock(&rtc->ops_lock);
        return err;
 }
+
+int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+       int err;
+       struct rtc_time before, now;
+       int first_time = 1;
+
+       /* The lower level RTC driver may not be capable of filling
+        * in all fields of the rtc_time struct (eg. rtc-cmos),
+        * and so might instead return -1 in some fields.
+        * We deal with that here by grabbing a current RTC timestamp
+        * and using values from that for any missing (-1) values.
+        *
+        * But this can be racey, because some fields of the RTC timestamp
+        * may have wrapped in the interval since we read the RTC alarm,
+        * which would lead to us inserting inconsistent values in place
+        * of the -1 fields.
+        *
+        * Reading the alarm and timestamp in the reverse sequence
+        * would have the same race condition, and not solve the issue.
+        *
+        * So, we must first read the RTC timestamp,
+        * then read the RTC alarm value,
+        * and then read a second RTC timestamp.
+        *
+        * If any fields of the second timestamp have changed
+        * when compared with the first timestamp, then we know
+        * our timestamp may be inconsistent with that used by
+        * the low-level rtc_read_alarm_internal() function.
+        *
+        * So, when the two timestamps disagree, we just loop and do
+        * the process again to get a fully consistent set of values.
+        *
+        * This could all instead be done in the lower level driver,
+        * but since more than one lower level RTC implementation needs it,
+        * then it's probably best best to do it here instead of there..
+        */
+
+       /* Get the "before" timestamp */
+       err = rtc_read_time(rtc, &before);
+       if (err < 0)
+               return err;
+       do {
+               if (!first_time)
+                       memcpy(&before, &now, sizeof(struct rtc_time));
+               first_time = 0;
+
+               /* get the RTC alarm values, which may be incomplete */
+               err = rtc_read_alarm_internal(rtc, alarm);
+               if (err)
+                       return err;
+               if (!alarm->enabled)
+                       return 0;
+
+               /* get the "after" timestamp, to detect wrapped fields */
+               err = rtc_read_time(rtc, &now);
+               if (err < 0)
+                       return err;
+
+               /* note that tm_sec is a "don't care" value here: */
+       } while (   before.tm_min   != now.tm_min
+                || before.tm_hour  != now.tm_hour
+                || before.tm_mon   != now.tm_mon
+                || before.tm_year  != now.tm_year
+                || before.tm_isdst != now.tm_isdst);
+
+       /* Fill in any missing alarm fields using the timestamp */
+       if (alarm->time.tm_sec == -1)
+               alarm->time.tm_sec = now.tm_sec;
+       if (alarm->time.tm_min == -1)
+               alarm->time.tm_min = now.tm_min;
+       if (alarm->time.tm_hour == -1)
+               alarm->time.tm_hour = now.tm_hour;
+       if (alarm->time.tm_mday == -1)
+               alarm->time.tm_mday = now.tm_mday;
+       if (alarm->time.tm_mon == -1)
+               alarm->time.tm_mon = now.tm_mon;
+       if (alarm->time.tm_year == -1)
+               alarm->time.tm_year = now.tm_year;
+       return 0;
+}
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
 
 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to