forked from mirrors/linux
		
	driver core: class.c: convert to only use class_to_subsys
Now that class_to_subsys() can be used to get access to the internal class private pointer, convert the remaining few places in class.c that were accessing the pointer directly to use class_to_subsys() instead. By doing this, the need for class_get() and class_put() goes away as no one actually tries to increment the class structures anymore, only the internal dynamic one. Cc: "Rafael J. Wysocki" <rafael@kernel.org> Link: https://lore.kernel.org/r/20230325194234.46588-2-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									884f8ce42c
								
							
						
					
					
						commit
						7b884b7f24
					
				
					 1 changed files with 61 additions and 52 deletions
				
			
		|  | @ -66,24 +66,6 @@ static struct subsys_private *class_to_subsys(const struct class *class) | ||||||
| 	return sp; | 	return sp; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct class *class_get(const struct class *class) |  | ||||||
| { |  | ||||||
| 	struct subsys_private *sp = class_to_subsys(class); |  | ||||||
| 
 |  | ||||||
| 	if (sp) |  | ||||||
| 		return class; |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void class_put(const struct class *class) |  | ||||||
| { |  | ||||||
| 	struct subsys_private *sp = class_to_subsys(class); |  | ||||||
| 
 |  | ||||||
| 	/* two puts are required as the call to bus_to_subsys incremented it again */ |  | ||||||
| 	subsys_put(sp); |  | ||||||
| 	subsys_put(sp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, | static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, | ||||||
| 			       char *buf) | 			       char *buf) | ||||||
| { | { | ||||||
|  | @ -148,13 +130,15 @@ static const struct kobj_type class_ktype = { | ||||||
| int class_create_file_ns(const struct class *cls, const struct class_attribute *attr, | int class_create_file_ns(const struct class *cls, const struct class_attribute *attr, | ||||||
| 			 const void *ns) | 			 const void *ns) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp = class_to_subsys(cls); | ||||||
| 	int error; | 	int error; | ||||||
| 
 | 
 | ||||||
| 	if (cls) | 	if (!sp) | ||||||
| 		error = sysfs_create_file_ns(&cls->p->subsys.kobj, | 		return -EINVAL; | ||||||
| 					     &attr->attr, ns); | 
 | ||||||
| 	else | 	error = sysfs_create_file_ns(&sp->subsys.kobj, &attr->attr, ns); | ||||||
| 		error = -EINVAL; | 	subsys_put(sp); | ||||||
|  | 
 | ||||||
| 	return error; | 	return error; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(class_create_file_ns); | EXPORT_SYMBOL_GPL(class_create_file_ns); | ||||||
|  | @ -162,8 +146,13 @@ EXPORT_SYMBOL_GPL(class_create_file_ns); | ||||||
| void class_remove_file_ns(const struct class *cls, const struct class_attribute *attr, | void class_remove_file_ns(const struct class *cls, const struct class_attribute *attr, | ||||||
| 			  const void *ns) | 			  const void *ns) | ||||||
| { | { | ||||||
| 	if (cls) | 	struct subsys_private *sp = class_to_subsys(cls); | ||||||
| 		sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); | 
 | ||||||
|  | 	if (!sp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	sysfs_remove_file_ns(&sp->subsys.kobj, &attr->attr, ns); | ||||||
|  | 	subsys_put(sp); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(class_remove_file_ns); | EXPORT_SYMBOL_GPL(class_remove_file_ns); | ||||||
| 
 | 
 | ||||||
|  | @ -187,18 +176,6 @@ static void klist_class_dev_put(struct klist_node *n) | ||||||
| 	put_device(dev); | 	put_device(dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int class_add_groups(const struct class *cls, |  | ||||||
| 			    const struct attribute_group **groups) |  | ||||||
| { |  | ||||||
| 	return sysfs_create_groups(&cls->p->subsys.kobj, groups); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void class_remove_groups(const struct class *cls, |  | ||||||
| 				const struct attribute_group **groups) |  | ||||||
| { |  | ||||||
| 	return sysfs_remove_groups(&cls->p->subsys.kobj, groups); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int class_register(struct class *cls) | int class_register(struct class *cls) | ||||||
| { | { | ||||||
| 	struct subsys_private *cp; | 	struct subsys_private *cp; | ||||||
|  | @ -235,8 +212,7 @@ int class_register(struct class *cls) | ||||||
| 	if (error) | 	if (error) | ||||||
| 		goto err_out; | 		goto err_out; | ||||||
| 
 | 
 | ||||||
| 	error = class_add_groups(class_get(cls), cls->class_groups); | 	error = sysfs_create_groups(&cp->subsys.kobj, cls->class_groups); | ||||||
| 	class_put(cls); |  | ||||||
| 	if (error) { | 	if (error) { | ||||||
| 		kobject_del(&cp->subsys.kobj); | 		kobject_del(&cp->subsys.kobj); | ||||||
| 		kfree_const(cp->subsys.kobj.name); | 		kfree_const(cp->subsys.kobj.name); | ||||||
|  | @ -253,9 +229,16 @@ EXPORT_SYMBOL_GPL(class_register); | ||||||
| 
 | 
 | ||||||
| void class_unregister(const struct class *cls) | void class_unregister(const struct class *cls) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp = class_to_subsys(cls); | ||||||
|  | 
 | ||||||
|  | 	if (!sp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	pr_debug("device class '%s': unregistering\n", cls->name); | 	pr_debug("device class '%s': unregistering\n", cls->name); | ||||||
| 	class_remove_groups(cls, cls->class_groups); | 
 | ||||||
| 	kset_unregister(&cls->p->subsys); | 	sysfs_remove_groups(&sp->subsys.kobj, cls->class_groups); | ||||||
|  | 	kset_unregister(&sp->subsys); | ||||||
|  | 	subsys_put(sp); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(class_unregister); | EXPORT_SYMBOL_GPL(class_unregister); | ||||||
| 
 | 
 | ||||||
|  | @ -334,11 +317,15 @@ EXPORT_SYMBOL_GPL(class_destroy); | ||||||
| void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, | void class_dev_iter_init(struct class_dev_iter *iter, const struct class *class, | ||||||
| 			 const struct device *start, const struct device_type *type) | 			 const struct device *start, const struct device_type *type) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp = class_to_subsys(class); | ||||||
| 	struct klist_node *start_knode = NULL; | 	struct klist_node *start_knode = NULL; | ||||||
| 
 | 
 | ||||||
|  | 	if (!sp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	if (start) | 	if (start) | ||||||
| 		start_knode = &start->p->knode_class; | 		start_knode = &start->p->knode_class; | ||||||
| 	klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); | 	klist_iter_init_node(&sp->klist_devices, &iter->ki, start_knode); | ||||||
| 	iter->type = type; | 	iter->type = type; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(class_dev_iter_init); | EXPORT_SYMBOL_GPL(class_dev_iter_init); | ||||||
|  | @ -405,13 +392,14 @@ EXPORT_SYMBOL_GPL(class_dev_iter_exit); | ||||||
| int class_for_each_device(const struct class *class, const struct device *start, | int class_for_each_device(const struct class *class, const struct device *start, | ||||||
| 			  void *data, int (*fn)(struct device *, void *)) | 			  void *data, int (*fn)(struct device *, void *)) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp = class_to_subsys(class); | ||||||
| 	struct class_dev_iter iter; | 	struct class_dev_iter iter; | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
| 	int error = 0; | 	int error = 0; | ||||||
| 
 | 
 | ||||||
| 	if (!class) | 	if (!class) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	if (!class->p) { | 	if (!sp) { | ||||||
| 		WARN(1, "%s called for class '%s' before it was initialized", | 		WARN(1, "%s called for class '%s' before it was initialized", | ||||||
| 		     __func__, class->name); | 		     __func__, class->name); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
|  | @ -424,6 +412,7 @@ int class_for_each_device(const struct class *class, const struct device *start, | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	class_dev_iter_exit(&iter); | 	class_dev_iter_exit(&iter); | ||||||
|  | 	subsys_put(sp); | ||||||
| 
 | 
 | ||||||
| 	return error; | 	return error; | ||||||
| } | } | ||||||
|  | @ -453,12 +442,13 @@ struct device *class_find_device(const struct class *class, const struct device | ||||||
| 				 const void *data, | 				 const void *data, | ||||||
| 				 int (*match)(struct device *, const void *)) | 				 int (*match)(struct device *, const void *)) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp = class_to_subsys(class); | ||||||
| 	struct class_dev_iter iter; | 	struct class_dev_iter iter; | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
| 
 | 
 | ||||||
| 	if (!class) | 	if (!class) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	if (!class->p) { | 	if (!sp) { | ||||||
| 		WARN(1, "%s called for class '%s' before it was initialized", | 		WARN(1, "%s called for class '%s' before it was initialized", | ||||||
| 		     __func__, class->name); | 		     __func__, class->name); | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -472,6 +462,7 @@ struct device *class_find_device(const struct class *class, const struct device | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	class_dev_iter_exit(&iter); | 	class_dev_iter_exit(&iter); | ||||||
|  | 	subsys_put(sp); | ||||||
| 
 | 
 | ||||||
| 	return dev; | 	return dev; | ||||||
| } | } | ||||||
|  | @ -479,6 +470,7 @@ EXPORT_SYMBOL_GPL(class_find_device); | ||||||
| 
 | 
 | ||||||
| int class_interface_register(struct class_interface *class_intf) | int class_interface_register(struct class_interface *class_intf) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp; | ||||||
| 	const struct class *parent; | 	const struct class *parent; | ||||||
| 	struct class_dev_iter iter; | 	struct class_dev_iter iter; | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
|  | @ -486,19 +478,25 @@ int class_interface_register(struct class_interface *class_intf) | ||||||
| 	if (!class_intf || !class_intf->class) | 	if (!class_intf || !class_intf->class) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	parent = class_get(class_intf->class); | 	parent = class_intf->class; | ||||||
| 	if (!parent) | 	sp = class_to_subsys(parent); | ||||||
|  | 	if (!sp) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&parent->p->mutex); | 	/*
 | ||||||
| 	list_add_tail(&class_intf->node, &parent->p->interfaces); | 	 * Reference in sp is now incremented and will be dropped when | ||||||
|  | 	 * the interface is removed in the call to class_interface_unregister() | ||||||
|  | 	 */ | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&sp->mutex); | ||||||
|  | 	list_add_tail(&class_intf->node, &sp->interfaces); | ||||||
| 	if (class_intf->add_dev) { | 	if (class_intf->add_dev) { | ||||||
| 		class_dev_iter_init(&iter, parent, NULL, NULL); | 		class_dev_iter_init(&iter, parent, NULL, NULL); | ||||||
| 		while ((dev = class_dev_iter_next(&iter))) | 		while ((dev = class_dev_iter_next(&iter))) | ||||||
| 			class_intf->add_dev(dev, class_intf); | 			class_intf->add_dev(dev, class_intf); | ||||||
| 		class_dev_iter_exit(&iter); | 		class_dev_iter_exit(&iter); | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&parent->p->mutex); | 	mutex_unlock(&sp->mutex); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -506,6 +504,7 @@ EXPORT_SYMBOL_GPL(class_interface_register); | ||||||
| 
 | 
 | ||||||
| void class_interface_unregister(struct class_interface *class_intf) | void class_interface_unregister(struct class_interface *class_intf) | ||||||
| { | { | ||||||
|  | 	struct subsys_private *sp; | ||||||
| 	struct class *parent = class_intf->class; | 	struct class *parent = class_intf->class; | ||||||
| 	struct class_dev_iter iter; | 	struct class_dev_iter iter; | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
|  | @ -513,7 +512,11 @@ void class_interface_unregister(struct class_interface *class_intf) | ||||||
| 	if (!parent) | 	if (!parent) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&parent->p->mutex); | 	sp = class_to_subsys(parent); | ||||||
|  | 	if (!sp) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&sp->mutex); | ||||||
| 	list_del_init(&class_intf->node); | 	list_del_init(&class_intf->node); | ||||||
| 	if (class_intf->remove_dev) { | 	if (class_intf->remove_dev) { | ||||||
| 		class_dev_iter_init(&iter, parent, NULL, NULL); | 		class_dev_iter_init(&iter, parent, NULL, NULL); | ||||||
|  | @ -521,9 +524,15 @@ void class_interface_unregister(struct class_interface *class_intf) | ||||||
| 			class_intf->remove_dev(dev, class_intf); | 			class_intf->remove_dev(dev, class_intf); | ||||||
| 		class_dev_iter_exit(&iter); | 		class_dev_iter_exit(&iter); | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&parent->p->mutex); | 	mutex_unlock(&sp->mutex); | ||||||
| 
 | 
 | ||||||
| 	class_put(parent); | 	/*
 | ||||||
|  | 	 * Decrement the reference count twice, once for the class_to_subsys() | ||||||
|  | 	 * call in the start of this function, and the second one from the | ||||||
|  | 	 * reference increment in class_interface_register() | ||||||
|  | 	 */ | ||||||
|  | 	subsys_put(sp); | ||||||
|  | 	subsys_put(sp); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(class_interface_unregister); | EXPORT_SYMBOL_GPL(class_interface_unregister); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Greg Kroah-Hartman
						Greg Kroah-Hartman