W1: clean-up slave device implementation: - get rid of separate refcount, rely on driver model to enforce lifetime rules; - pin w1 module until slave device is registered with sysfs to make sure W1 core stays loaded. - drop 'name' attribute as we already have it in bus_id. Signed-off-by: Dmitry Torokhov <dtor at mail.ru> --- w1.c | 165 ++++++++++++++++++++++++------------------------------------ w1.h | 3 - w1_family.c | 2 w1_family.h | 2 w1_smem.c | 18 ------ w1_therm.c | 20 ------- 6 files changed, 71 insertions(+), 139 deletions(-) Index: dtor/drivers/w1/w1.c =================================================================== --- dtor.orig/drivers/w1/w1.c +++ dtor/drivers/w1/w1.c @@ -108,9 +108,6 @@ static ssize_t w1_default_read_bin(struc return sprintf(buf, "No family registered.\n"); } -static struct device_attribute w1_slave_attribute = - __ATTR(name, S_IRUGO, w1_default_read_name, NULL); - static struct device_attribute w1_slave_attribute_val = __ATTR(value, S_IRUGO, w1_default_read_name, NULL); @@ -126,166 +123,138 @@ static struct bin_attribute w1_slave_bin static void w1_slave_release(struct device *dev) { - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); + struct w1_slave *slave = to_w1_slave(dev); - complete(&sl->dev_released); + w1_family_put(slave->family); + kfree(slave); + module_put(THIS_MODULE); } -static int __w1_attach_slave_device(struct w1_slave *sl) +static int __w1_attach_slave_device(struct w1_slave *slave) { int err; - sl->dev.parent = &sl->master->dev; - sl->dev.bus = &w1_bus_type; - sl->dev.release = &w1_slave_release; + slave->dev.parent = &slave->master->dev; + slave->dev.bus = &w1_bus_type; + slave->dev.release = &w1_slave_release; - snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), - "%02x-%012llx", - (unsigned int) sl->reg_num.family, - (unsigned long long) sl->reg_num.id); - snprintf (&sl->name[0], sizeof(sl->name), + snprintf(&slave->dev.bus_id[0], sizeof(slave->dev.bus_id), "%02x-%012llx", - (unsigned int) sl->reg_num.family, - (unsigned long long) sl->reg_num.id); + (unsigned int) slave->reg_num.family, + (unsigned long long) slave->reg_num.id); - dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, - &sl->dev.bus_id[0]); + dev_dbg(&slave->dev, "%s: registering %s.\n", __func__, + &slave->dev.bus_id[0]); - err = device_register(&sl->dev); + err = device_register(&slave->dev); if (err < 0) { - dev_err(&sl->dev, + dev_err(&slave->dev, "Device registration [%s] failed. err=%d\n", - sl->dev.bus_id, err); + slave->dev.bus_id, err); return err; } - memcpy(&sl->attr_bin, &w1_slave_bin_attribute, sizeof(sl->attr_bin)); - memcpy(&sl->attr_name, &w1_slave_attribute, sizeof(sl->attr_name)); - memcpy(&sl->attr_val, &w1_slave_attribute_val, sizeof(sl->attr_val)); - - sl->attr_bin.read = sl->family->fops->rbin; - sl->attr_name.show = sl->family->fops->rname; - sl->attr_val.show = sl->family->fops->rval; - sl->attr_val.attr.name = sl->family->fops->rvalname; + __module_get(THIS_MODULE); - err = device_create_file(&sl->dev, &sl->attr_name); - if (err < 0) { - dev_err(&sl->dev, - "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - device_unregister(&sl->dev); - return err; - } + memcpy(&slave->attr_bin, &w1_slave_bin_attribute, sizeof(slave->attr_bin)); + memcpy(&slave->attr_val, &w1_slave_attribute_val, sizeof(slave->attr_val)); - err = device_create_file(&sl->dev, &sl->attr_val); + slave->attr_bin.read = slave->family->fops->rbin; + slave->attr_val.show = slave->family->fops->rval; + slave->attr_val.attr.name = slave->family->fops->rvalname; + + err = device_create_file(&slave->dev, &slave->attr_val); if (err < 0) { - dev_err(&sl->dev, + dev_err(&slave->dev, "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - device_remove_file(&sl->dev, &sl->attr_name); - device_unregister(&sl->dev); + slave->dev.bus_id, err); + device_unregister(&slave->dev); return err; } - err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); + err = sysfs_create_bin_file(&slave->dev.kobj, &slave->attr_bin); if (err < 0) { - dev_err(&sl->dev, + dev_err(&slave->dev, "sysfs file creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - device_remove_file(&sl->dev, &sl->attr_name); - device_remove_file(&sl->dev, &sl->attr_val); - device_unregister(&sl->dev); + slave->dev.bus_id, err); + device_remove_file(&slave->dev, &slave->attr_val); + device_unregister(&slave->dev); return err; } - err = sysfs_create_group(&sl->dev.kobj, &w1_slave_defattr_group); + err = sysfs_create_group(&slave->dev.kobj, &w1_slave_defattr_group); if (err < 0) { - dev_err(&sl->dev, + dev_err(&slave->dev, "sysfs group creation for [%s] failed. err=%d\n", - sl->dev.bus_id, err); - sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin); - device_remove_file(&sl->dev, &sl->attr_name); - device_remove_file(&sl->dev, &sl->attr_val); - device_unregister(&sl->dev); + slave->dev.bus_id, err); + sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin); + device_remove_file(&slave->dev, &slave->attr_val); + device_unregister(&slave->dev); return err; } - list_add_tail(&sl->node, &sl->master->slist); + list_add_tail(&slave->node, &slave->master->slist); return 0; } -static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) +static int w1_attach_slave_device(struct w1_master *master, struct w1_reg_num *rn) { - struct w1_slave *sl; + struct w1_slave *slave; struct w1_family *f; int err; - sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL); - if (!sl) { - dev_err(&dev->dev, + slave = kcalloc(1, sizeof(struct w1_slave), GFP_KERNEL); + if (!slave) { + dev_err(&master->dev, "%s: failed to allocate new slave device.\n", __func__); return -ENOMEM; } - memset(sl, 0, sizeof(*sl)); - - sl->master = dev; - set_bit(W1_SLAVE_ACTIVE, &sl->flags); - - memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); - atomic_set(&sl->refcnt, 0); - init_completion(&sl->dev_released); + slave->master = master; + slave->reg_num = *rn; + set_bit(W1_SLAVE_ACTIVE, &slave->flags); spin_lock(&w1_flock); f = w1_family_registered(rn->family); if (!f) { spin_unlock(&w1_flock); - dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n", - rn->family, rn->family, - (unsigned long long)rn->id, rn->crc); - kfree(sl); + dev_info(&master->dev, + "Family %x for %02x.%012llx.%02x is not registered.\n", + rn->family, rn->family, + (unsigned long long)rn->id, rn->crc); + kfree(slave); return -ENODEV; } __w1_family_get(f); spin_unlock(&w1_flock); - sl->family = f; + slave->family = f; - - err = __w1_attach_slave_device(sl); + err = __w1_attach_slave_device(slave); if (err < 0) { - dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__, - sl->name); - w1_family_put(sl->family); - kfree(sl); + dev_err(&master->dev, "%s: Attaching %s failed.\n", __func__, + slave->dev.bus_id); + w1_family_put(slave->family); + kfree(slave); return err; } - sl->ttl = dev->slave_ttl; + slave->ttl = master->slave_ttl; return 0; } -static void w1_slave_detach(struct w1_slave *sl) +static void w1_slave_detach(struct w1_slave *slave) { - dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name); + dev_info(&slave->dev, "%s: detaching %s.\n", + __func__, slave->dev.bus_id); - while (atomic_read(&sl->refcnt)) { - printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n", - sl->name, atomic_read(&sl->refcnt)); - - if (msleep_interruptible(1000)) - flush_signals(current); - } - - sysfs_remove_group(&sl->dev.kobj, &w1_slave_defattr_group); - sysfs_remove_bin_file(&sl->dev.kobj, &sl->attr_bin); - device_remove_file(&sl->dev, &sl->attr_name); - device_remove_file(&sl->dev, &sl->attr_val); - device_unregister(&sl->dev); - w1_family_put(sl->family); + sysfs_remove_group(&slave->dev.kobj, &w1_slave_defattr_group); + sysfs_remove_bin_file(&slave->dev.kobj, &slave->attr_bin); + device_remove_file(&slave->dev, &slave->attr_val); + device_unregister(&slave->dev); } static void w1_slave_found(struct w1_master *dev, u64 rn) @@ -333,7 +302,6 @@ static void w1_master_scan_slaves(struct !--slave->ttl) { list_del(&slave->node); w1_slave_detach(slave); - kfree(slave); } } up(&master->mutex); @@ -554,7 +522,6 @@ void w1_remove_master_device(struct w1_m list_for_each_entry_safe(slave, next, &master->slist, node) { list_del(&slave->node); w1_slave_detach(slave); - kfree(slave); } sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); Index: dtor/drivers/w1/w1.h =================================================================== --- dtor.orig/drivers/w1/w1.h +++ dtor/drivers/w1/w1.h @@ -62,10 +62,8 @@ struct w1_reg_num struct w1_slave { - unsigned char name[W1_MAXNAMELEN]; struct list_head node; struct w1_reg_num reg_num; - atomic_t refcnt; u8 rom[9]; unsigned long flags; int ttl; @@ -73,7 +71,6 @@ struct w1_slave struct w1_master *master; struct w1_family *family; struct device dev; - struct completion dev_released; struct bin_attribute attr_bin; struct device_attribute attr_name, attr_val; Index: dtor/drivers/w1/w1_therm.c =================================================================== --- dtor.orig/drivers/w1/w1_therm.c +++ dtor/drivers/w1/w1_therm.c @@ -41,24 +41,15 @@ static u8 bad_roms[][9] = { {} }; -static ssize_t w1_therm_read_name(struct device *, char *); static ssize_t w1_therm_read_temp(struct device *, char *); static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_therm_fops = { - .rname = &w1_therm_read_name, .rbin = &w1_therm_read_bin, .rval = &w1_therm_read_temp, .rvalname = "temp1_input", }; -static ssize_t w1_therm_read_name(struct device *dev, char *buf) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - - return sprintf(buf, "%s\n", sl->name); -} - static inline int w1_convert_temp(u8 rom[9]) { int t, h; @@ -102,12 +93,8 @@ static ssize_t w1_therm_read_bin(struct u8 rom[9], crc, verdict; int i, max_trying = 10; - atomic_inc(&sl->refcnt); - smp_mb__after_atomic_inc(); - if (down_interruptible(&sl->master->mutex)) { - count = 0; - goto out_dec; - } + if (down_interruptible(&sl->master->mutex)) + return 0; if (off > W1_SLAVE_DATA_SIZE) { count = 0; @@ -178,9 +165,6 @@ static ssize_t w1_therm_read_bin(struct count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom)); out: up(&dev->mutex); -out_dec: - smp_mb__before_atomic_inc(); - atomic_dec(&sl->refcnt); return count; } Index: dtor/drivers/w1/w1_smem.c =================================================================== --- dtor.orig/drivers/w1/w1_smem.c +++ dtor/drivers/w1/w1_smem.c @@ -35,24 +35,15 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeniy Polyakov <johnpol at 2ka.mipt.ru>"); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family."); -static ssize_t w1_smem_read_name(struct device *, char *); static ssize_t w1_smem_read_val(struct device *, char *); static ssize_t w1_smem_read_bin(struct kobject *, char *, loff_t, size_t); static struct w1_family_ops w1_smem_fops = { - .rname = &w1_smem_read_name, .rbin = &w1_smem_read_bin, .rval = &w1_smem_read_val, .rvalname = "id", }; -static ssize_t w1_smem_read_name(struct device *dev, char *buf) -{ - struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - - return sprintf(buf, "%s\n", sl->name); -} - static ssize_t w1_smem_read_val(struct device *dev, char *buf) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); @@ -72,11 +63,8 @@ static ssize_t w1_smem_read_bin(struct k struct w1_slave, dev); int i; - atomic_inc(&sl->refcnt); - if (down_interruptible(&sl->master->mutex)) { - count = 0; - goto out_dec; - } + if (down_interruptible(&sl->master->mutex)) + return 0; if (off > W1_SLAVE_DATA_SIZE) { count = 0; @@ -92,8 +80,6 @@ static ssize_t w1_smem_read_bin(struct k out: up(&sl->master->mutex); -out_dec: - atomic_dec(&sl->refcnt); return count; } Index: dtor/drivers/w1/w1_family.c =================================================================== --- dtor.orig/drivers/w1/w1_family.c +++ dtor/drivers/w1/w1_family.c @@ -30,7 +30,7 @@ static LIST_HEAD(w1_families); static int w1_check_family(struct w1_family *f) { - if (!f->fops->rname || !f->fops->rbin || !f->fops->rval || !f->fops->rvalname) + if (!f->fops->rbin || !f->fops->rval || !f->fops->rvalname) return -EINVAL; return 0; Index: dtor/drivers/w1/w1_family.h =================================================================== --- dtor.orig/drivers/w1/w1_family.h +++ dtor/drivers/w1/w1_family.h @@ -34,9 +34,7 @@ struct w1_family_ops { - ssize_t (* rname)(struct device *, char *); ssize_t (* rbin)(struct kobject *, char *, loff_t, size_t); - ssize_t (* rval)(struct device *, char *); unsigned char rvalname[MAXNAMELEN]; };