In many rtc modules, the chardevice file in rtc module probe is being created prematurely. If the probe fails after the chardevice file has been created (e.g. after rtc_device_register), it's possible for a program to open() it, which subsequently can cause memory corruption.
The race looks like that (thanks Jiri): CPU0: CPU1: sys_load_module() do_init_module() do_one_initcall() cmos_do_probe() rtc_device_register() __register_chrdev() cdev->owner = struct module* open("/dev/rtc0") rtc_device_unregister() module_put() free_module() module_free(mod->module_core) /* struct module *module is now freed */ chrdev_open() spin_lock(cdev_lock) cdev_get() try_module_get() module_is_live() /* dereferences already freed struct module* */ This patch is proposing a solution, splitting the function {devm_,}rtc_device_register into {devm_,}rtc_device_register{_fs,}. The {devm_}rtc_device_register_fs which is creating the files, should be called after it is clear that the probe will pass. It will set the RTC_DEV_FILES_EXIST into rtc_device->flags. In case of probe not passing, the rtc_device_unregister will try to delete the files only if RTC_DEV_FILES_EXIST is set in rtc_device->flags. Acked-by: Jiri Kosina <jkos...@suse.cz> Signed-off-by: Ales Novak <alno...@suse.cz> --- drivers/rtc/class.c | 47 ++++++++++++++++++++++++++++++++-------------- drivers/rtc/rtc-ab8500.c | 1 + drivers/rtc/rtc-at91sam9.c | 2 ++ drivers/rtc/rtc-bfin.c | 2 ++ drivers/rtc/rtc-cmos.c | 2 ++ drivers/rtc/rtc-davinci.c | 2 ++ drivers/rtc/rtc-ds1305.c | 2 ++ drivers/rtc/rtc-ds1307.c | 2 ++ drivers/rtc/rtc-ds1511.c | 2 ++ drivers/rtc/rtc-ds1553.c | 2 ++ drivers/rtc/rtc-ds1672.c | 2 ++ drivers/rtc/rtc-ds1742.c | 2 ++ drivers/rtc/rtc-ds3232.c | 2 ++ drivers/rtc/rtc-ep93xx.c | 2 ++ drivers/rtc/rtc-isl1208.c | 2 ++ drivers/rtc/rtc-jz4740.c | 2 ++ drivers/rtc/rtc-m41t80.c | 2 ++ drivers/rtc/rtc-m48t59.c | 2 ++ drivers/rtc/rtc-max8998.c | 1 + drivers/rtc/rtc-mrst.c | 2 ++ drivers/rtc/rtc-nuc900.c | 2 ++ drivers/rtc/rtc-omap.c | 2 ++ drivers/rtc/rtc-pcap.c | 2 ++ drivers/rtc/rtc-pcf2123.c | 1 + drivers/rtc/rtc-pl031.c | 2 ++ drivers/rtc/rtc-r9701.c | 2 ++ drivers/rtc/rtc-rp5c01.c | 2 ++ drivers/rtc/rtc-rs5c372.c | 2 ++ drivers/rtc/rtc-rv3029c2.c | 1 + drivers/rtc/rtc-rx8025.c | 2 ++ drivers/rtc/rtc-spear.c | 2 ++ drivers/rtc/rtc-stk17ta8.c | 2 ++ drivers/rtc/rtc-stmp3xxx.c | 2 ++ drivers/rtc/rtc-tegra.c | 2 ++ drivers/rtc/rtc-test.c | 2 ++ drivers/rtc/rtc-twl.c | 3 +++ drivers/rtc/rtc-tx4939.c | 3 +++ drivers/rtc/rtc-vr41xx.c | 2 ++ drivers/rtc/rtc-vt8500.c | 2 ++ drivers/rtc/rtc-x1205.c | 2 ++ include/linux/rtc.h | 7 ++++++- 41 files changed, 115 insertions(+), 15 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 589351e..6af8355 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -230,13 +230,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, goto exit_kfree; } - rtc_dev_add_device(rtc); - rtc_sysfs_add_device(rtc); - rtc_proc_add_device(rtc); - - dev_info(dev, "rtc core: registered %s as %s\n", - rtc->name, dev_name(&rtc->dev)); - return rtc; exit_kfree: @@ -252,6 +245,21 @@ exit: } EXPORT_SYMBOL_GPL(rtc_device_register); +/** + * rtc_device_register_fs - creates dev+sysfs+proc files + * for rtc device + */ +void rtc_device_register_fs(struct device *dev, struct rtc_device *rtc) +{ + rtc_dev_add_device(rtc); + rtc_sysfs_add_device(rtc); + rtc_proc_add_device(rtc); + + set_bit(RTC_DEV_FILES_EXIST, &rtc->flags); + dev_info(dev, "rtc core: registered %s as %s\n", + rtc->name, dev_name(&rtc->dev)); +} +EXPORT_SYMBOL_GPL(rtc_device_register_fs); /** * rtc_device_unregister - removes the previously registered RTC class device @@ -262,13 +270,15 @@ void rtc_device_unregister(struct rtc_device *rtc) { if (get_device(&rtc->dev) != NULL) { mutex_lock(&rtc->ops_lock); - /* remove innards of this RTC, then disable it, before - * letting any rtc_class_open() users access it again - */ - rtc_sysfs_del_device(rtc); - rtc_dev_del_device(rtc); - rtc_proc_del_device(rtc); - device_unregister(&rtc->dev); + if (test_and_clear_bit(RTC_DEV_FILES_EXIST, &rtc->flags)) { + /* remove innards of this RTC, then disable it, before + * letting any rtc_class_open() users access it again + */ + rtc_sysfs_del_device(rtc); + rtc_dev_del_device(rtc); + rtc_proc_del_device(rtc); + device_unregister(&rtc->dev); + } rtc->ops = NULL; mutex_unlock(&rtc->ops_lock); put_device(&rtc->dev); @@ -328,6 +338,15 @@ struct rtc_device *devm_rtc_device_register(struct device *dev, EXPORT_SYMBOL_GPL(devm_rtc_device_register); /** + * devm_rtc_device_register_fs - create proc&dev&sys files for the rtc device + */ +void devm_rtc_device_register_fs(struct device *dev, struct rtc_device *rtc) +{ + rtc_device_register_fs(dev, rtc); +} +EXPORT_SYMBOL_GPL(devm_rtc_device_register_fs); + +/** * devm_rtc_device_unregister - resource managed devm_rtc_device_unregister() * @dev: the device to unregister * @rtc: the RTC class device to unregister diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 727e2f5..8e25da6 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -503,6 +503,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "sysfs RTC failed to register\n"); return err; } + devm_rtc_device_register_fs(&pdev->dev, rtc); return 0; } diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 309b8b3..0108c6a 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -369,6 +369,8 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "%s: SET TIME!\n", dev_name(&rtc->rtcdev->dev)); + devm_rtc_device_register_fs(&pdev->dev, rtc); + return 0; } diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 0c53f45..a7190b8 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -380,6 +380,8 @@ static int bfin_rtc_probe(struct platform_device *pdev) bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE); bfin_write_RTC_SWCNT(0); + devm_rtc_device_register_fs(&pdev->dev, rtc->rtc_dev); + return 0; err: diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index cae212f..fff8b9d 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -784,6 +784,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup2; } + rtc_device_register_fs(dev, cmos_rtc.rtc); + dev_info(dev, "%s%s, %zd bytes nvram%s\n", !is_valid_irq(rtc_irq) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 24677ef8..57467ac 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -554,6 +554,8 @@ static int __init davinci_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); + devm_rtc_device_register_fs(&pdev->dev, davinci_rtc->rtc); + return 0; } diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 2dd586a..fb85d20 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -771,6 +771,8 @@ static int ds1305_probe(struct spi_device *spi) return status; } + devm_rtc_device_register_fs(&spi->dev, ds1305->rtc); + return 0; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 4e75345..31cffee 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -972,6 +972,8 @@ read_rtc: dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size); } + devm_rtc_device_register_fs(&client->dev, ds1307->rtc); + return 0; err_irq: diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index bc7b4fc..14f076d 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -534,6 +534,8 @@ static int ds1511_rtc_probe(struct platform_device *pdev) ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); + devm_rtc_device_register_fs(&pdev->dev, rtc); + return ret; } diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index fd31571..735ea10 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -329,6 +329,8 @@ static int ds1553_rtc_probe(struct platform_device *pdev) ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); + devm_rtc_device_register_fs(&pdev->dev, rtc); + return ret; } diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 18e2d84..2ad2578 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -189,6 +189,8 @@ static int ds1672_probe(struct i2c_client *client, if (err) goto exit_devreg; + devm_rtc_device_register_fs(&client->dev, rtc); + return 0; exit_devreg: diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 5a1f3b2..d4444b0 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -205,6 +205,8 @@ static int ds1742_rtc_probe(struct platform_device *pdev) ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); + devm_rtc_device_register_fs(&pdev->dev, rtc); + return ret; } diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index b83bb5a5..778a9d5 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -427,6 +427,8 @@ static int ds3232_probe(struct i2c_client *client, } } + devm_rtc_device_register_fs(&client->dev, ds3232->rtc); + return 0; } diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 5e4f5dc..fbe9a01 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -156,6 +156,8 @@ static int ep93xx_rtc_probe(struct platform_device *pdev) if (err) goto exit; + devm_rtc_device_register_fs(&pdev->dev, ep93xx_rtc->rtc); + return 0; exit: diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index c3c549d..bc25c5b 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -681,6 +681,8 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) if (rc) return rc; + devm_rtc_device_register_fs(&client->dev, rtc); + return 0; } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 1b126d2..925600b 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -278,6 +278,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev) } } + devm_rtc_device_register_fs(&pdev->dev, rtc->rtc); + return 0; } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a5248aa..cd51429 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -707,6 +707,8 @@ static int m41t80_probe(struct i2c_client *client, } } #endif + devm_rtc_device_register_fs(&client->dev, rtc); + return 0; st_err: diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 11880c1..027bcbd 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -489,6 +489,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev) if (ret) return ret; + devm_rtc_device_register_fs(&pdev->dev, m48t59->rtc); + return 0; } diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index f098ad8..c74020d 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -300,6 +300,7 @@ no_irq: dev_warn(&pdev->dev, "LP3974 with RTC REGERR option." " RTC updates will be extremely slow.\n"); } + devm_rtc_device_register_fs(&pdev->dev, rtc); return 0; } diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index e2436d1..f61a2ef 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -374,6 +374,7 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, goto cleanup1; } } + rtc_device_register_fs(dev, mrst_rtc.rtc); dev_dbg(dev, "initialised\n"); return 0; @@ -403,6 +404,7 @@ static void rtc_mrst_do_remove(struct device *dev) if (mrst->irq) free_irq(mrst->irq, mrst->rtc); + rtc_device_unregister_fs(mrst->rtc); rtc_device_unregister(mrst->rtc); mrst->rtc = NULL; diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index 248653c..64dd6e2 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -257,6 +257,8 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev) return -EBUSY; } + devm_rtc_device_register_fs(&pdev->dev, nuc900_rtc->rtc); + return 0; } diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 26de5f8..5fb141f 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -449,6 +449,8 @@ static int __init omap_rtc_probe(struct platform_device *pdev) if (reg != new_ctrl) rtc_write(new_ctrl, OMAP_RTC_CTRL_REG); + devm_rtc_device_register_fs(&pdev->dev, rtc); + return 0; fail0: diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index 40b5c63..9aaac77 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -172,6 +172,8 @@ static int __init pcap_rtc_probe(struct platform_device *pdev) if (err) return err; + devm_rtc_device_register_fs(&pdev->dev, pcap_rtc->rtc); + return 0; } diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index d1953bb..874d85d 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -313,6 +313,7 @@ static int pcf2123_probe(struct spi_device *spi) goto sysfs_exit; } } + devm_rtc_device_register_fs(&spi->dev, rtc); return 0; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 99181fff..5f04b29 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -306,6 +306,7 @@ static int pl031_remove(struct amba_device *adev) struct pl031_local *ldata = dev_get_drvdata(&adev->dev); free_irq(adev->irq[0], ldata); + rtc_device_unregister_fs(ldata->rtc); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); kfree(ldata); @@ -384,6 +385,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) goto out_no_irq; } + rtc_device_register_fs(&adev->dev, ldata->rtc); return 0; out_no_irq: diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index feeedbd..5f39f64 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -161,6 +161,8 @@ static int r9701_probe(struct spi_device *spi) spi_set_drvdata(spi, rtc); + devm_rtc_device_register_fs(&spi->dev, rtc); + return 0; } diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 89d0736..83d8655 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -259,6 +259,8 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev) if (error) return error; + devm_rtc_device_register_fs(&dev->dev, rtc); + return 0; } diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index ccf54f0..a426eca 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -668,6 +668,8 @@ static int rs5c372_probe(struct i2c_client *client, if (err) goto exit; + devm_rtc_device_register_fs(&client->dev, rs5c372->rtc); + return 0; exit: diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 1a779a6..57e7d2e 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -408,6 +408,7 @@ static int rv3029c2_probe(struct i2c_client *client, dev_err(&client->dev, "reading status failed\n"); return rc; } + devm_rtc_device_register_fs(&client->dev, rtc); return 0; } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 8fa23ea..b07fac1 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -597,6 +597,8 @@ static int rx8025_probe(struct i2c_client *client, if (err) goto errout_irq; + devm_rtc_device_register_fs(&client->dev, rx8025->rtc); + return 0; errout_irq: diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index c492cf0..a644636 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -414,6 +414,8 @@ static int spear_rtc_probe(struct platform_device *pdev) if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); + devm_rtc_device_register_fs(&pdev->dev, config->rtc); + return 0; err_disable_clock: diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index a176ba6..ec53d2a 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -338,6 +338,8 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev) ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); + devm_rtc_device_register_fs(&pdev->dev, pdata->rtc); + return ret; } diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index ea96492..0d8c575 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -304,6 +304,8 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) return err; } + devm_rtc_device_register_fs(&pdev->dev, rtc_data->rtc); + stmp3xxx_wdt_register(pdev); return 0; } diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 76af92a..084d1ab 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -365,6 +365,8 @@ static int __init tegra_rtc_probe(struct platform_device *pdev) dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); + devm_rtc_device_register_fs(&pdev->dev, info->rtc_dev); + return 0; } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 7746e65..0737eca 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -114,6 +114,8 @@ static int test_probe(struct platform_device *plat_dev) platform_set_drvdata(plat_dev, rtc); + devm_rtc_device_register_fs(&plat_dev->dev, rtc); + return 0; err: diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 1915464..e9614e8 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -544,6 +544,9 @@ static int twl_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); + + devm_rtc_device_register_fs(&pdev->dev, rtc); + return 0; } diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4f87234..40b68f93 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -269,6 +269,9 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) pdata->rtc = rtc; ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + if (!ret) + devm_rtc_device_register_fs(&pdev->dev, rtc); + return ret; } diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 88c9c92..d84865b 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -355,6 +355,8 @@ static int rtc_probe(struct platform_device *pdev) disable_irq(aie_irq); disable_irq(pie_irq); + devm_rtc_device_register_fs(&pdev->dev, rtc); + dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n"); return 0; diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index df2ef3e..121f544 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -269,6 +269,8 @@ static int vt8500_rtc_probe(struct platform_device *pdev) goto err_return; } + devm_rtc_device_register_fs(&pdev->dev, vt8500_rtc->rtc); + return 0; err_return: diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 365dc65..679df80 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -662,6 +662,8 @@ static int x1205_probe(struct i2c_client *client, if (err) return err; + devm_rtc_device_register_fs(&client->dev, rtc); + return 0; } diff --git a/include/linux/rtc.h b/include/linux/rtc.h index c2c2897..245432a 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h @@ -81,7 +81,9 @@ struct rtc_timer { /* flags */ -#define RTC_DEV_BUSY 0 +#define RTC_DEV_BUSY 0 +/* flag indicating the files for the device have been created */ +#define RTC_DEV_FILES_EXIST 1 struct rtc_device { @@ -133,10 +135,13 @@ extern struct rtc_device *rtc_device_register(const char *name, struct device *dev, const struct rtc_class_ops *ops, struct module *owner); + +extern void rtc_device_register_fs(struct device *dev, struct rtc_device *rtc); extern struct rtc_device *devm_rtc_device_register(struct device *dev, const char *name, const struct rtc_class_ops *ops, struct module *owner); +extern void devm_rtc_device_register_fs(struct device *dev, struct rtc_device *rtc); extern void rtc_device_unregister(struct rtc_device *rtc); extern void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc); -- 1.8.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/