IB/core: Fix kobject leak on device register error flow
[linux-2.6-block.git] / drivers / infiniband / core / sysfs.c
index 68fa798c007dd97bddf631f42ef72cc098fc175c..cbd0383f622e0311bd4f56652648609604cb94c4 100644 (file)
@@ -816,6 +816,22 @@ static struct attribute_group iw_stats_group = {
        .attrs  = iw_proto_stats_attrs,
 };
 
+static void free_port_list_attributes(struct ib_device *device)
+{
+       struct kobject *p, *t;
+
+       list_for_each_entry_safe(p, t, &device->port_list, entry) {
+               struct ib_port *port = container_of(p, struct ib_port, kobj);
+               list_del(&p->entry);
+               sysfs_remove_group(p, &pma_group);
+               sysfs_remove_group(p, &port->pkey_group);
+               sysfs_remove_group(p, &port->gid_group);
+               kobject_put(p);
+       }
+
+       kobject_put(device->ports_parent);
+}
+
 int ib_device_register_sysfs(struct ib_device *device,
                             int (*port_callback)(struct ib_device *,
                                                  u8, struct kobject *))
@@ -869,19 +885,7 @@ int ib_device_register_sysfs(struct ib_device *device,
        return 0;
 
 err_put:
-       {
-               struct kobject *p, *t;
-               struct ib_port *port;
-
-               list_for_each_entry_safe(p, t, &device->port_list, entry) {
-                       list_del(&p->entry);
-                       port = container_of(p, struct ib_port, kobj);
-                       sysfs_remove_group(p, &pma_group);
-                       sysfs_remove_group(p, &port->pkey_group);
-                       sysfs_remove_group(p, &port->gid_group);
-                       kobject_put(p);
-               }
-       }
+       free_port_list_attributes(device);
 
 err_unregister:
        device_unregister(class_dev);
@@ -892,22 +896,18 @@ err:
 
 void ib_device_unregister_sysfs(struct ib_device *device)
 {
-       struct kobject *p, *t;
-       struct ib_port *port;
-
        /* Hold kobject until ib_dealloc_device() */
-       kobject_get(&device->dev.kobj);
+       struct kobject *kobj_dev = kobject_get(&device->dev.kobj);
+       int i;
 
-       list_for_each_entry_safe(p, t, &device->port_list, entry) {
-               list_del(&p->entry);
-               port = container_of(p, struct ib_port, kobj);
-               sysfs_remove_group(p, &pma_group);
-               sysfs_remove_group(p, &port->pkey_group);
-               sysfs_remove_group(p, &port->gid_group);
-               kobject_put(p);
-       }
+       if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats)
+               sysfs_remove_group(kobj_dev, &iw_stats_group);
+
+       free_port_list_attributes(device);
+
+       for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i)
+               device_remove_file(&device->dev, ib_class_attributes[i]);
 
-       kobject_put(device->ports_parent);
        device_unregister(&device->dev);
 }