Pull xpc-disengage into release branch
[sfrench/cifs-2.6.git] / drivers / base / attribute_container.c
index 62c093db11e6e853c7b8d5c22ca1603f904aea07..6b2eb6f39b4dea6ec809acb715cf1c2ab1fc0b45 100644 (file)
 /* This is a private structure used to tie the classdev and the
  * container .. it should never be visible outside this file */
 struct internal_container {
-       struct list_head node;
+       struct klist_node node;
        struct attribute_container *cont;
        struct class_device classdev;
 };
 
+static void internal_container_klist_get(struct klist_node *n)
+{
+       struct internal_container *ic =
+               container_of(n, struct internal_container, node);
+       class_device_get(&ic->classdev);
+}
+
+static void internal_container_klist_put(struct klist_node *n)
+{
+       struct internal_container *ic =
+               container_of(n, struct internal_container, node);
+       class_device_put(&ic->classdev);
+}
+
+
 /**
  * attribute_container_classdev_to_container - given a classdev, return the container
  *
@@ -57,8 +72,8 @@ int
 attribute_container_register(struct attribute_container *cont)
 {
        INIT_LIST_HEAD(&cont->node);
-       INIT_LIST_HEAD(&cont->containers);
-       spin_lock_init(&cont->containers_lock);
+       klist_init(&cont->containers,internal_container_klist_get,
+                  internal_container_klist_put);
                
        down(&attribute_container_mutex);
        list_add_tail(&cont->node, &attribute_container_list);
@@ -78,13 +93,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))
+       spin_lock(&cont->containers.k_lock);
+       if (!list_empty(&cont->containers.k_list))
                goto out;
        retval = 0;
        list_del(&cont->node);
  out:
-       spin_unlock(&cont->containers_lock);
+       spin_unlock(&cont->containers.k_lock);
        up(&attribute_container_mutex);
        return retval;
                
@@ -137,13 +152,13 @@ attribute_container_add_device(struct device *dev,
 
                if (!cont->match(cont, dev))
                        continue;
-               ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL);
+
+               ic = kzalloc(sizeof(*ic), GFP_KERNEL);
                if (!ic) {
                        dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
                        continue;
                }
-               memset(ic, 0, sizeof(struct internal_container));
-               INIT_LIST_HEAD(&ic->node);
+
                ic->cont = cont;
                class_device_initialize(&ic->classdev);
                ic->classdev.dev = get_device(dev);
@@ -154,13 +169,22 @@ 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);
+               klist_add_tail(&ic->node, &cont->containers);
        }
        up(&attribute_container_mutex);
 }
 
+/* FIXME: can't break out of this unless klist_iter_exit is also
+ * called before doing the break
+ */
+#define klist_for_each_entry(pos, head, member, iter) \
+       for (klist_iter_init(head, iter); (pos = ({ \
+               struct klist_node *n = klist_next(iter); \
+               n ? container_of(n, typeof(*pos), member) : \
+                       ({ klist_iter_exit(iter) ; NULL; }); \
+       }) ) != NULL; )
+                       
+
 /**
  * attribute_container_remove_device - make device eligible for removal.
  *
@@ -187,18 +211,19 @@ attribute_container_remove_device(struct device *dev,
 
        down(&attribute_container_mutex);
        list_for_each_entry(cont, &attribute_container_list, node) {
-               struct internal_container *ic, *tmp;
+               struct internal_container *ic;
+               struct klist_iter iter;
 
                if (attribute_container_no_classdevs(cont))
                        continue;
 
                if (!cont->match(cont, dev))
                        continue;
-               spin_lock(&cont->containers_lock);
-               list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+
+               klist_for_each_entry(ic, &cont->containers, node, &iter) {
                        if (dev != ic->classdev.dev)
                                continue;
-                       list_del(&ic->node);
+                       klist_del(&ic->node);
                        if (fn)
                                fn(cont, dev, &ic->classdev);
                        else {
@@ -206,7 +231,6 @@ attribute_container_remove_device(struct device *dev,
                                class_device_unregister(&ic->classdev);
                        }
                }
-               spin_unlock(&cont->containers_lock);
        }
        up(&attribute_container_mutex);
 }
@@ -232,17 +256,21 @@ attribute_container_device_trigger(struct device *dev,
 
        down(&attribute_container_mutex);
        list_for_each_entry(cont, &attribute_container_list, node) {
-               struct internal_container *ic, *tmp;
+               struct internal_container *ic;
+               struct klist_iter iter;
 
                if (!cont->match(cont, dev))
                        continue;
 
-               spin_lock(&cont->containers_lock);
-               list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+               if (attribute_container_no_classdevs(cont)) {
+                       fn(cont, dev, NULL);
+                       continue;
+               }
+
+               klist_for_each_entry(ic, &cont->containers, node, &iter) {
                        if (dev == ic->classdev.dev)
                                fn(cont, dev, &ic->classdev);
                }
-               spin_unlock(&cont->containers_lock);
        }
        up(&attribute_container_mutex);
 }
@@ -392,15 +420,16 @@ attribute_container_find_class_device(struct attribute_container *cont,
 {
        struct class_device *cdev = NULL;
        struct internal_container *ic;
+       struct klist_iter iter;
 
-       spin_lock(&cont->containers_lock);
-       list_for_each_entry(ic, &cont->containers, node) {
+       klist_for_each_entry(ic, &cont->containers, node, &iter) {
                if (ic->classdev.dev == dev) {
                        cdev = &ic->classdev;
+                       /* FIXME: must exit iterator then break */
+                       klist_iter_exit(&iter);
                        break;
                }
        }
-       spin_unlock(&cont->containers_lock);
 
        return cdev;
 }