IB/core: Make ib_alloc_device init the kobject
authorJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Tue, 4 Aug 2015 21:23:34 +0000 (15:23 -0600)
committerDoug Ledford <dledford@redhat.com>
Sun, 30 Aug 2015 22:08:50 +0000 (18:08 -0400)
This gets rid of the weird in-between state where struct ib_device
was allocated but the kobject didn't work.

Consequently ib_device_release is now guaranteed to be called in
all situations and we needn't duplicate its kfrees on error paths.

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/cache.c
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/sysfs.c

index c93af66cc091a8e9faa354e32538268e6217d0c7..a6d50258131e0729c974e9cedbcc47ad95f36196 100644 (file)
@@ -351,10 +351,10 @@ static void ib_cache_setup_one(struct ib_device *device)
        rwlock_init(&device->cache.lock);
 
        device->cache.pkey_cache =
-               kmalloc(sizeof *device->cache.pkey_cache *
+               kzalloc(sizeof *device->cache.pkey_cache *
                        (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL);
        device->cache.gid_cache =
-               kmalloc(sizeof *device->cache.gid_cache *
+               kzalloc(sizeof *device->cache.gid_cache *
                        (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL);
 
        device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache *
@@ -369,11 +369,8 @@ static void ib_cache_setup_one(struct ib_device *device)
                goto err;
        }
 
-       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) {
-               device->cache.pkey_cache[p] = NULL;
-               device->cache.gid_cache [p] = NULL;
+       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p)
                ib_cache_update(device, p + rdma_start_port(device));
-       }
 
        INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
                              device, ib_cache_event);
index 87d1936f5c1caa93e188af91e9aefb1e6484902b..950583a62e3b7e371474d9c0b5044de6bca08c81 100644 (file)
@@ -43,9 +43,6 @@ int  ib_device_register_sysfs(struct ib_device *device,
                                                   u8, struct kobject *));
 void ib_device_unregister_sysfs(struct ib_device *device);
 
-int  ib_sysfs_setup(void);
-void ib_sysfs_cleanup(void);
-
 int  ib_cache_setup(void);
 void ib_cache_cleanup(void);
 
index a9a27816991ab444073edbaeb4a47e3400c031af..a4a914afae1c15f5fe38dfdea76489dafc9e36c6 100644 (file)
@@ -165,6 +165,35 @@ static int alloc_name(char *name)
        return 0;
 }
 
+static void ib_device_release(struct device *device)
+{
+       struct ib_device *dev = container_of(device, struct ib_device, dev);
+
+       kfree(dev->port_immutable);
+       kfree(dev);
+}
+
+static int ib_device_uevent(struct device *device,
+                           struct kobj_uevent_env *env)
+{
+       struct ib_device *dev = container_of(device, struct ib_device, dev);
+
+       if (add_uevent_var(env, "NAME=%s", dev->name))
+               return -ENOMEM;
+
+       /*
+        * It would be nice to pass the node GUID with the event...
+        */
+
+       return 0;
+}
+
+static struct class ib_class = {
+       .name    = "infiniband",
+       .dev_release = ib_device_release,
+       .dev_uevent = ib_device_uevent,
+};
+
 /**
  * ib_alloc_device - allocate an IB device struct
  * @size:size of structure to allocate
@@ -177,9 +206,27 @@ static int alloc_name(char *name)
  */
 struct ib_device *ib_alloc_device(size_t size)
 {
-       BUG_ON(size < sizeof (struct ib_device));
+       struct ib_device *device;
+
+       if (WARN_ON(size < sizeof(struct ib_device)))
+               return NULL;
+
+       device = kzalloc(size, GFP_KERNEL);
+       if (!device)
+               return NULL;
+
+       device->dev.class = &ib_class;
+       device_initialize(&device->dev);
+
+       dev_set_drvdata(&device->dev, device);
+
+       INIT_LIST_HEAD(&device->event_handler_list);
+       spin_lock_init(&device->event_handler_lock);
+       spin_lock_init(&device->client_data_lock);
+       INIT_LIST_HEAD(&device->client_data_list);
+       INIT_LIST_HEAD(&device->port_list);
 
-       return kzalloc(size, GFP_KERNEL);
+       return device;
 }
 EXPORT_SYMBOL(ib_alloc_device);
 
@@ -191,13 +238,8 @@ EXPORT_SYMBOL(ib_alloc_device);
  */
 void ib_dealloc_device(struct ib_device *device)
 {
-       if (device->reg_state == IB_DEV_UNINITIALIZED) {
-               kfree(device);
-               return;
-       }
-
-       BUG_ON(device->reg_state != IB_DEV_UNREGISTERED);
-
+       WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
+               device->reg_state != IB_DEV_UNINITIALIZED);
        kobject_put(&device->dev.kobj);
 }
 EXPORT_SYMBOL(ib_dealloc_device);
@@ -235,7 +277,7 @@ static int verify_immutable(const struct ib_device *dev, u8 port)
 
 static int read_port_immutable(struct ib_device *device)
 {
-       int ret = -ENOMEM;
+       int ret;
        u8 start_port = rdma_start_port(device);
        u8 end_port = rdma_end_port(device);
        u8 port;
@@ -251,26 +293,18 @@ static int read_port_immutable(struct ib_device *device)
                                         * (end_port + 1),
                                         GFP_KERNEL);
        if (!device->port_immutable)
-               goto err;
+               return -ENOMEM;
 
        for (port = start_port; port <= end_port; ++port) {
                ret = device->get_port_immutable(device, port,
                                                 &device->port_immutable[port]);
                if (ret)
-                       goto err;
+                       return ret;
 
-               if (verify_immutable(device, port)) {
-                       ret = -EINVAL;
-                       goto err;
-               }
+               if (verify_immutable(device, port))
+                       return -EINVAL;
        }
-
-       ret = 0;
-       goto out;
-err:
-       kfree(device->port_immutable);
-out:
-       return ret;
+       return 0;
 }
 
 /**
@@ -301,11 +335,6 @@ int ib_register_device(struct ib_device *device,
                goto out;
        }
 
-       INIT_LIST_HEAD(&device->event_handler_list);
-       INIT_LIST_HEAD(&device->client_data_list);
-       spin_lock_init(&device->event_handler_lock);
-       spin_lock_init(&device->client_data_lock);
-
        ret = read_port_immutable(device);
        if (ret) {
                printk(KERN_WARNING "Couldn't create per port immutable data %s\n",
@@ -317,7 +346,6 @@ int ib_register_device(struct ib_device *device,
        if (ret) {
                printk(KERN_WARNING "Couldn't register device %s with driver model\n",
                       device->name);
-               kfree(device->port_immutable);
                goto out;
        }
 
@@ -834,7 +862,7 @@ static int __init ib_core_init(void)
        if (!ib_wq)
                return -ENOMEM;
 
-       ret = ib_sysfs_setup();
+       ret = class_register(&ib_class);
        if (ret) {
                printk(KERN_WARNING "Couldn't create InfiniBand device class\n");
                goto err;
@@ -858,7 +886,7 @@ err_nl:
        ibnl_cleanup();
 
 err_sysfs:
-       ib_sysfs_cleanup();
+       class_unregister(&ib_class);
 
 err:
        destroy_workqueue(ib_wq);
@@ -869,7 +897,7 @@ static void __exit ib_core_cleanup(void)
 {
        ib_cache_cleanup();
        ibnl_cleanup();
-       ib_sysfs_cleanup();
+       class_unregister(&ib_class);
        /* Make sure that any pending umem accounting work is done. */
        destroy_workqueue(ib_wq);
 }
index 0b84a9cdfe5b90636d3633dbb42d84ef84c4e98e..34cdd74b0a17ed06228bf78f134c2001c976125a 100644 (file)
@@ -457,29 +457,6 @@ static struct kobj_type port_type = {
        .default_attrs = port_default_attrs
 };
 
-static void ib_device_release(struct device *device)
-{
-       struct ib_device *dev = container_of(device, struct ib_device, dev);
-
-       kfree(dev->port_immutable);
-       kfree(dev);
-}
-
-static int ib_device_uevent(struct device *device,
-                           struct kobj_uevent_env *env)
-{
-       struct ib_device *dev = container_of(device, struct ib_device, dev);
-
-       if (add_uevent_var(env, "NAME=%s", dev->name))
-               return -ENOMEM;
-
-       /*
-        * It would be nice to pass the node GUID with the event...
-        */
-
-       return 0;
-}
-
 static struct attribute **
 alloc_group_attrs(ssize_t (*show)(struct ib_port *,
                                  struct port_attribute *, char *buf),
@@ -702,12 +679,6 @@ static struct device_attribute *ib_class_attributes[] = {
        &dev_attr_node_desc
 };
 
-static struct class ib_class = {
-       .name    = "infiniband",
-       .dev_release = ib_device_release,
-       .dev_uevent = ib_device_uevent,
-};
-
 /* Show a given an attribute in the statistics group */
 static ssize_t show_protocol_stat(const struct device *device,
                            struct device_attribute *attr, char *buf,
@@ -846,14 +817,12 @@ int ib_device_register_sysfs(struct ib_device *device,
        int ret;
        int i;
 
-       class_dev->class      = &ib_class;
-       class_dev->parent     = device->dma_device;
-       dev_set_name(class_dev, "%s", device->name);
-       dev_set_drvdata(class_dev, device);
-
-       INIT_LIST_HEAD(&device->port_list);
+       device->dev.parent = device->dma_device;
+       ret = dev_set_name(class_dev, "%s", device->name);
+       if (ret)
+               return ret;
 
-       ret = device_register(class_dev);
+       ret = device_add(class_dev);
        if (ret)
                goto err;
 
@@ -916,13 +885,3 @@ void ib_device_unregister_sysfs(struct ib_device *device)
 
        device_unregister(&device->dev);
 }
-
-int ib_sysfs_setup(void)
-{
-       return class_register(&ib_class);
-}
-
-void ib_sysfs_cleanup(void)
-{
-       class_unregister(&ib_class);
-}