]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
greybus: Unregister devices to get them freed
authorViresh Kumar <viresh.kumar@linaro.org>
Thu, 2 Apr 2015 12:23:47 +0000 (17:53 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Sun, 5 Apr 2015 14:23:22 +0000 (16:23 +0200)
Devices registered with the device-core needs to be freed by calling
device_unregister(). For module we are calling just put_device() and for
bundle, connection and interface we are calling device_del().

All of these are incomplete and so none of them get freed, i.e. the
.release() routine is never called for their devices.

Module being a special case that it needs to maintain a refcount or a
list of interfaces to trace its usage count. I have chosen refcount.

And so once the refcount is zero, we can Unregister the device and
module will get free as well.

Because of this bug in freeing devices, their sysfs directories were not
getting removed properly and after a manifest is parsed with the help of
gbsim, removing modules was creating problems. The sysfs directory
'greybus' wasn't getting removed. And inserting the modules again
resulted in warnings and insmod failure.

WARNING: CPU: 3 PID: 4277 at
/build/buildd/linux-3.13.0/fs/sysfs/dir.c:486
sysfs_warn_dup+0x86/0xa0()

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/bundle.c
drivers/staging/greybus/connection.c
drivers/staging/greybus/interface.c
drivers/staging/greybus/module.c
drivers/staging/greybus/module.h

index 93f80dc5a8154a76336b346b03b01f00183d979a..5ced992e17d4d8faa74352c0d524bb9ac3fd1285 100644 (file)
@@ -140,7 +140,7 @@ void gb_bundle_destroy(struct gb_interface *intf)
        list_for_each_entry_safe(bundle, temp, &list, links) {
                list_del(&bundle->links);
                gb_bundle_connections_exit(bundle);
-               device_del(&bundle->dev);
+               device_unregister(&bundle->dev);
        }
 }
 
index 102e1a4c6e745439dcba977e53f3896783157484..5ec161b9b2f28cd78e032c9676f5a6598e7ceb95 100644 (file)
@@ -252,7 +252,7 @@ void gb_connection_destroy(struct gb_connection *connection)
        gb_connection_hd_cport_id_free(connection);
        gb_protocol_put(connection->protocol);
 
-       device_del(&connection->dev);
+       device_unregister(&connection->dev);
 }
 
 int gb_connection_init(struct gb_connection *connection)
index b687908cfa16d7ba0164f5a50f1e78fe0458a5e8..122281f2cd2b0739ad3303926d0ee0902095088f 100644 (file)
@@ -173,6 +173,8 @@ static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
  */
 static void gb_interface_destroy(struct gb_interface *intf)
 {
+       struct gb_module *module;
+
        if (WARN_ON(!intf))
                return;
 
@@ -184,10 +186,11 @@ static void gb_interface_destroy(struct gb_interface *intf)
 
        kfree(intf->product_string);
        kfree(intf->vendor_string);
-       put_device(&intf->module->dev);
        /* kref_put(module->hd); */
 
-       device_del(&intf->dev);
+       module = intf->module;
+       device_unregister(&intf->dev);
+       gb_module_remove(module);
 }
 
 /**
index 56a55fea107b4968f7e6662f5868153d8d80de77..538182b60dd921433dccfd8281f7d77c4763f28f 100644 (file)
@@ -101,6 +101,7 @@ static struct gb_module *gb_module_create(struct greybus_host_device *hd,
                return NULL;
 
        module->module_id = module_id;
+       module->refcount = 1;
        module->dev.parent = hd->parent;
        module->dev.bus = &greybus_bus_type;
        module->dev.type = &greybus_module_type;
@@ -127,9 +128,20 @@ struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
        struct gb_module *module;
 
        module = gb_module_find(module_id);
-       if (module)
+       if (module) {
+               module->refcount++;
                return module;
+       }
 
        return gb_module_create(hd, module_id);
 }
 
+void gb_module_remove(struct gb_module *module)
+{
+       if (!module)
+               return;
+
+       if (!--module->refcount)
+               device_unregister(&module->dev);
+}
+
index 75a8818de1c51af9a01d2a9a4aa5762daa114c2b..4f02e46301e1bc31d4a6427ab520052e10c631f3 100644 (file)
@@ -13,6 +13,7 @@
 struct gb_module {
        struct device dev;
        u8 module_id;           /* Physical location within the Endo */
+       u16 refcount;
 };
 #define to_gb_module(d) container_of(d, struct gb_module, dev)
 
@@ -21,6 +22,7 @@ struct greybus_host_device;
 /* Greybus "private" definitions */
 struct gb_module *gb_module_find_or_create(struct greybus_host_device *hd,
                                           u8 module_id);
+void gb_module_remove(struct gb_module *module);
 
 
 #endif /* __MODULE_H */