diff options
| -rw-r--r-- | drivers/base/attribute_container.c | 38 | ||||
| -rw-r--r-- | drivers/base/transport_class.c | 17 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 6 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_spi.c | 11 | ||||
| -rw-r--r-- | include/linux/attribute_container.h | 9 | ||||
| -rw-r--r-- | include/linux/transport_class.h | 11 | 
6 files changed, 72 insertions, 20 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index ec615d854be..62c093db11e 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont)  {  	INIT_LIST_HEAD(&cont->node);  	INIT_LIST_HEAD(&cont->containers); +	spin_lock_init(&cont->containers_lock);  	down(&attribute_container_mutex);  	list_add_tail(&cont->node, &attribute_container_list); @@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont)  {  	int retval = -EBUSY;  	down(&attribute_container_mutex); +	spin_lock(&cont->containers_lock);  	if (!list_empty(&cont->containers))  		goto out;  	retval = 0;  	list_del(&cont->node);   out: +	spin_unlock(&cont->containers_lock);  	up(&attribute_container_mutex);  	return retval; @@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev,  			fn(cont, dev, &ic->classdev);  		else  			attribute_container_add_class_device(&ic->classdev); +		spin_lock(&cont->containers_lock);  		list_add_tail(&ic->node, &cont->containers); +		spin_unlock(&cont->containers_lock);  	}  	up(&attribute_container_mutex);  } @@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev,  		if (!cont->match(cont, dev))  			continue; +		spin_lock(&cont->containers_lock);  		list_for_each_entry_safe(ic, tmp, &cont->containers, node) {  			if (dev != ic->classdev.dev)  				continue; @@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev,  				class_device_unregister(&ic->classdev);  			}  		} +		spin_unlock(&cont->containers_lock);  	}  	up(&attribute_container_mutex);  } @@ -230,10 +237,12 @@ attribute_container_device_trigger(struct device *dev,  		if (!cont->match(cont, dev))  			continue; +		spin_lock(&cont->containers_lock);  		list_for_each_entry_safe(ic, tmp, &cont->containers, node) {  			if (dev == ic->classdev.dev)  				fn(cont, dev, &ic->classdev);  		} +		spin_unlock(&cont->containers_lock);  	}  	up(&attribute_container_mutex);  } @@ -368,6 +377,35 @@ attribute_container_class_device_del(struct class_device *classdev)  }  EXPORT_SYMBOL_GPL(attribute_container_class_device_del); +/** + * attribute_container_find_class_device - find the corresponding class_device + * + * @cont:	the container + * @dev:	the generic device + * + * Looks up the device in the container's list of class devices and returns + * the corresponding class_device. + */ +struct class_device * +attribute_container_find_class_device(struct attribute_container *cont, +				      struct device *dev) +{ +	struct class_device *cdev = NULL; +	struct internal_container *ic; + +	spin_lock(&cont->containers_lock); +	list_for_each_entry(ic, &cont->containers, node) { +		if (ic->classdev.dev == dev) { +			cdev = &ic->classdev; +			break; +		} +	} +	spin_unlock(&cont->containers_lock); + +	return cdev; +} +EXPORT_SYMBOL_GPL(attribute_container_find_class_device); +  int __init  attribute_container_init(void)  { diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 6c2b447a333..4fb4c5de847 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass)  }  EXPORT_SYMBOL_GPL(transport_class_unregister); -static int anon_transport_dummy_function(struct device *dev) +static int anon_transport_dummy_function(struct transport_container *tc, +					 struct device *dev, +					 struct class_device *cdev)  {  	/* do nothing */  	return 0; @@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont,  				    struct class_device *classdev)  {  	struct transport_class *tclass = class_to_transport_class(cont->class); +	struct transport_container *tcont = attribute_container_to_transport_container(cont);  	if (tclass->setup) -		tclass->setup(dev); +		tclass->setup(tcont, dev, classdev);  	return 0;  } @@ -178,12 +181,14 @@ void transport_add_device(struct device *dev)  EXPORT_SYMBOL_GPL(transport_add_device);  static int transport_configure(struct attribute_container *cont, -			       struct device *dev) +			       struct device *dev, +			       struct class_device *cdev)  {  	struct transport_class *tclass = class_to_transport_class(cont->class); +	struct transport_container *tcont = attribute_container_to_transport_container(cont);  	if (tclass->configure) -		tclass->configure(dev); +		tclass->configure(tcont, dev, cdev);  	return 0;  } @@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont,   */  void transport_configure_device(struct device *dev)  { -	attribute_container_trigger(dev, transport_configure); +	attribute_container_device_trigger(dev, transport_configure);  }  EXPORT_SYMBOL_GPL(transport_configure_device); @@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont,  	struct transport_class *tclass = class_to_transport_class(cont->class);  	if (tclass->remove) -		tclass->remove(dev); +		tclass->remove(tcont, dev, classdev);  	if (tclass->remove != anon_transport_dummy_function) {  		if (tcont->statistics) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 35d1c1e8e34..96243c7fe11 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -252,7 +252,8 @@ struct fc_internal {  #define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t) -static int fc_target_setup(struct device *dev) +static int fc_target_setup(struct transport_container *tc, struct device *dev, +			   struct class_device *cdev)  {  	struct scsi_target *starget = to_scsi_target(dev);  	struct fc_rport *rport = starget_to_rport(starget); @@ -281,7 +282,8 @@ static DECLARE_TRANSPORT_CLASS(fc_transport_class,  			       NULL,  			       NULL); -static int fc_host_setup(struct device *dev) +static int fc_host_setup(struct transport_container *tc, struct device *dev, +			 struct class_device *cdev)  {  	struct Scsi_Host *shost = dev_to_shost(dev); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 02134fce217..89f6b7feb9c 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -162,7 +162,8 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name)  	return SPI_SIGNAL_UNKNOWN;  } -static int spi_host_setup(struct device *dev) +static int spi_host_setup(struct transport_container *tc, struct device *dev, +			  struct class_device *cdev)  {  	struct Scsi_Host *shost = dev_to_shost(dev); @@ -196,7 +197,9 @@ static int spi_host_match(struct attribute_container *cont,  	return &i->t.host_attrs.ac == cont;  } -static int spi_device_configure(struct device *dev) +static int spi_device_configure(struct transport_container *tc, +				struct device *dev, +				struct class_device *cdev)  {  	struct scsi_device *sdev = to_scsi_device(dev);  	struct scsi_target *starget = sdev->sdev_target; @@ -214,7 +217,9 @@ static int spi_device_configure(struct device *dev)  	return 0;  } -static int spi_setup_transport_attrs(struct device *dev) +static int spi_setup_transport_attrs(struct transport_container *tc, +				     struct device *dev, +				     struct class_device *cdev)  {  	struct scsi_target *starget = to_scsi_target(dev); diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index af1010b6dab..f54b05b052b 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -11,10 +11,12 @@  #include <linux/device.h>  #include <linux/list.h> +#include <linux/spinlock.h>  struct attribute_container {  	struct list_head	node;  	struct list_head	containers; +	spinlock_t		containers_lock;  	struct class		*class;  	struct class_device_attribute **attrs;  	int (*match)(struct attribute_container *, struct device *); @@ -62,12 +64,7 @@ int attribute_container_add_class_device_adapter(struct attribute_container *con  						 struct class_device *classdev);  void attribute_container_remove_attrs(struct class_device *classdev);  void attribute_container_class_device_del(struct class_device *classdev); - - - - - - +struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *);  struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev);  #endif diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h index 87d98d1faef..1d6cc22e5f4 100644 --- a/include/linux/transport_class.h +++ b/include/linux/transport_class.h @@ -12,11 +12,16 @@  #include <linux/device.h>  #include <linux/attribute_container.h> +struct transport_container; +  struct transport_class {  	struct class class; -	int (*setup)(struct device *); -	int (*configure)(struct device *); -	int (*remove)(struct device *); +	int (*setup)(struct transport_container *, struct device *, +		     struct class_device *); +	int (*configure)(struct transport_container *, struct device *, +			 struct class_device *); +	int (*remove)(struct transport_container *, struct device *, +		      struct class_device *);  };  #define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg)			\  |