diff options
author | David Brownell <david-b@pacbell.net> | 2007-02-28 23:12:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-01 17:53:37 -0500 |
commit | e109ebd1eed2b91e3c9bb3b42cc27961f0dc22b3 (patch) | |
tree | 402ca61d265c59d35282b0786363dfbe32659564 /drivers/rtc | |
parent | 0478e62e8a04154b7bdc0dfd33ffbcabc5446e9c (diff) |
[PATCH] rtc_cmos oops fix
Fix an oops on the rtc_device_unregister() path by waiting until the last
moment before nulling the rtc->ops vector. Fix some potential oopses by
having the rtc_class_open()/rtc_class_close() interface increase the RTC's
reference count while an RTC handle is available outside the RTC framework.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/class.c | 14 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 3 |
2 files changed, 12 insertions, 5 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 7a0d8ee2de9c..04aaa6347234 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -113,10 +113,16 @@ EXPORT_SYMBOL_GPL(rtc_device_register); | |||
113 | */ | 113 | */ |
114 | void rtc_device_unregister(struct rtc_device *rtc) | 114 | void rtc_device_unregister(struct rtc_device *rtc) |
115 | { | 115 | { |
116 | mutex_lock(&rtc->ops_lock); | 116 | if (class_device_get(&rtc->class_dev) != NULL) { |
117 | rtc->ops = NULL; | 117 | mutex_lock(&rtc->ops_lock); |
118 | mutex_unlock(&rtc->ops_lock); | 118 | /* remove innards of this RTC, then disable it, before |
119 | class_device_unregister(&rtc->class_dev); | 119 | * letting any rtc_class_open() users access it again |
120 | */ | ||
121 | class_device_unregister(&rtc->class_dev); | ||
122 | rtc->ops = NULL; | ||
123 | mutex_unlock(&rtc->ops_lock); | ||
124 | class_device_put(&rtc->class_dev); | ||
125 | } | ||
120 | } | 126 | } |
121 | EXPORT_SYMBOL_GPL(rtc_device_unregister); | 127 | EXPORT_SYMBOL_GPL(rtc_device_unregister); |
122 | 128 | ||
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 6f11f6dfdd9d..ef40df0f169d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -179,7 +179,7 @@ struct class_device *rtc_class_open(char *name) | |||
179 | down(&rtc_class->sem); | 179 | down(&rtc_class->sem); |
180 | list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { | 180 | list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { |
181 | if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { | 181 | if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { |
182 | class_dev = class_dev_tmp; | 182 | class_dev = class_device_get(class_dev_tmp); |
183 | break; | 183 | break; |
184 | } | 184 | } |
185 | } | 185 | } |
@@ -197,6 +197,7 @@ EXPORT_SYMBOL_GPL(rtc_class_open); | |||
197 | void rtc_class_close(struct class_device *class_dev) | 197 | void rtc_class_close(struct class_device *class_dev) |
198 | { | 198 | { |
199 | module_put(to_rtc_device(class_dev)->owner); | 199 | module_put(to_rtc_device(class_dev)->owner); |
200 | class_device_put(class_dev); | ||
200 | } | 201 | } |
201 | EXPORT_SYMBOL_GPL(rtc_class_close); | 202 | EXPORT_SYMBOL_GPL(rtc_class_close); |
202 | 203 | ||