aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-21 16:24:32 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-22 13:55:03 -0400
commit47eba33a0997fc7362ae41cf28cea687e28bd731 (patch)
treed20f1127549aca2a1add4f9ea02c919cb7549aea /drivers/w1/w1.c
parent3e1026b3fa2f61d33ce6a9e42a22398cc4ab8e58 (diff)
w1: remove race with sysfs file creation
W1 slave sysfs files are created _after_ userspace is notified that the device has been added to the system. Fix that race by moving the creation/remove of the files to the bus notifier that is there for doing this type of thing. Acked-by: Evgeniy Polyakov <zbr@ioremap.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/w1/w1.c')
-rw-r--r--drivers/w1/w1.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0459df843c58..3c798db0152c 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -587,6 +587,73 @@ end:
587 return err; 587 return err;
588} 588}
589 589
590/*
591 * Handle sysfs file creation and removal here, before userspace is told that
592 * the device is added / removed from the system
593 */
594static int w1_bus_notify(struct notifier_block *nb, unsigned long action,
595 void *data)
596{
597 struct device *dev = data;
598 struct w1_slave *sl;
599 int err;
600
601 /*
602 * Only care about slave devices at the moment. Yes, we should use a
603 * separate "type" for this, but for now, look at the release function
604 * to know which type it is...
605 */
606 if (dev->release != w1_slave_release)
607 return 0;
608
609 sl = dev_to_w1_slave(dev);
610
611 switch (action) {
612 case BUS_NOTIFY_ADD_DEVICE:
613 /* Create our sysfs files before userspace is told about it */
614 /* Create "name" entry */
615 err = device_create_file(&sl->dev, &w1_slave_attr_name);
616 if (err < 0) {
617 dev_err(&sl->dev,
618 "sysfs file creation for [%s] failed. err=%d\n",
619 dev_name(&sl->dev), err);
620 return err;
621 }
622
623 /* Create "id" entry */
624 err = device_create_file(&sl->dev, &w1_slave_attr_id);
625 if (err < 0) {
626 dev_err(&sl->dev,
627 "sysfs file creation for [%s] failed. err=%d\n",
628 dev_name(&sl->dev), err);
629 return err;
630 }
631
632 /* if the family driver needs to initialize something... */
633 if (sl->family->fops && sl->family->fops->add_slave &&
634 ((err = sl->family->fops->add_slave(sl)) < 0)) {
635 dev_err(&sl->dev,
636 "sysfs file creation for [%s] failed. err=%d\n",
637 dev_name(&sl->dev), err);
638 return err;
639 }
640
641 break;
642 case BUS_NOTIFY_DEL_DEVICE:
643 /* Remove our sysfs files */
644 if (sl->family->fops && sl->family->fops->remove_slave)
645 sl->family->fops->remove_slave(sl);
646 device_remove_file(&sl->dev, &w1_slave_attr_id);
647 device_remove_file(&sl->dev, &w1_slave_attr_name);
648 break;
649 }
650 return 0;
651}
652
653static struct notifier_block w1_bus_nb = {
654 .notifier_call = w1_bus_notify,
655};
656
590static int __w1_attach_slave_device(struct w1_slave *sl) 657static int __w1_attach_slave_device(struct w1_slave *sl)
591{ 658{
592 int err; 659 int err;
@@ -615,44 +682,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
615 return err; 682 return err;
616 } 683 }
617 684
618 /* Create "name" entry */
619 err = device_create_file(&sl->dev, &w1_slave_attr_name);
620 if (err < 0) {
621 dev_err(&sl->dev,
622 "sysfs file creation for [%s] failed. err=%d\n",
623 dev_name(&sl->dev), err);
624 goto out_unreg;
625 }
626
627 /* Create "id" entry */
628 err = device_create_file(&sl->dev, &w1_slave_attr_id);
629 if (err < 0) {
630 dev_err(&sl->dev,
631 "sysfs file creation for [%s] failed. err=%d\n",
632 dev_name(&sl->dev), err);
633 goto out_rem1;
634 }
635 685
636 /* if the family driver needs to initialize something... */ 686 dev_set_uevent_suppress(&sl->dev, false);
637 if (sl->family->fops && sl->family->fops->add_slave && 687 kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
638 ((err = sl->family->fops->add_slave(sl)) < 0)) {
639 dev_err(&sl->dev,
640 "sysfs file creation for [%s] failed. err=%d\n",
641 dev_name(&sl->dev), err);
642 goto out_rem2;
643 }
644 688
645 list_add_tail(&sl->w1_slave_entry, &sl->master->slist); 689 list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
646 690
647 return 0; 691 return 0;
648
649out_rem2:
650 device_remove_file(&sl->dev, &w1_slave_attr_id);
651out_rem1:
652 device_remove_file(&sl->dev, &w1_slave_attr_name);
653out_unreg:
654 device_unregister(&sl->dev);
655 return err;
656} 692}
657 693
658static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) 694static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
@@ -723,16 +759,11 @@ void w1_slave_detach(struct w1_slave *sl)
723 759
724 list_del(&sl->w1_slave_entry); 760 list_del(&sl->w1_slave_entry);
725 761
726 if (sl->family->fops && sl->family->fops->remove_slave)
727 sl->family->fops->remove_slave(sl);
728
729 memset(&msg, 0, sizeof(msg)); 762 memset(&msg, 0, sizeof(msg));
730 memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); 763 memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
731 msg.type = W1_SLAVE_REMOVE; 764 msg.type = W1_SLAVE_REMOVE;
732 w1_netlink_send(sl->master, &msg); 765 w1_netlink_send(sl->master, &msg);
733 766
734 device_remove_file(&sl->dev, &w1_slave_attr_id);
735 device_remove_file(&sl->dev, &w1_slave_attr_name);
736 device_unregister(&sl->dev); 767 device_unregister(&sl->dev);
737 768
738 wait_for_completion(&sl->released); 769 wait_for_completion(&sl->released);
@@ -1017,6 +1048,10 @@ static int __init w1_init(void)
1017 goto err_out_exit_init; 1048 goto err_out_exit_init;
1018 } 1049 }
1019 1050
1051 retval = bus_register_notifier(&w1_bus_type, &w1_bus_nb);
1052 if (retval)
1053 goto err_out_bus_unregister;
1054
1020 retval = driver_register(&w1_master_driver); 1055 retval = driver_register(&w1_master_driver);
1021 if (retval) { 1056 if (retval) {
1022 printk(KERN_ERR 1057 printk(KERN_ERR