aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2016-07-10 07:27:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-08-31 09:13:55 -0400
commitcebf8fd16900fdfd58c0028617944f808f97fe50 (patch)
treeb4042d299494ce09ce38e37186191456fd0dfa2b /drivers/base/core.c
parent24ef5f360f22e4408cb49d75755d27d5a21820f7 (diff)
driver core: fix race between creating/querying glue dir and its cleanup
The global mutex of 'gdp_mutex' is used to serialize creating/querying glue dir and its cleanup. Turns out it isn't a perfect way because part(kobj_kset_leave()) of the actual cleanup action() is done inside the release handler of the glue dir kobject. That means gdp_mutex has to be held before releasing the last reference count of the glue dir kobject. This patch moves glue dir's cleanup after kobject_del() in device_del() for avoiding the race. Cc: Yijing Wang <wangyijing@huawei.com> Reported-by: Chandra Sekhar Lingutla <clingutla@codeaurora.org> Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0a8bdade53f2..88df65d1e6f6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -836,11 +836,29 @@ static struct kobject *get_device_parent(struct device *dev,
836 return NULL; 836 return NULL;
837} 837}
838 838
839static inline bool live_in_glue_dir(struct kobject *kobj,
840 struct device *dev)
841{
842 if (!kobj || !dev->class ||
843 kobj->kset != &dev->class->p->glue_dirs)
844 return false;
845 return true;
846}
847
848static inline struct kobject *get_glue_dir(struct device *dev)
849{
850 return dev->kobj.parent;
851}
852
853/*
854 * make sure cleaning up dir as the last step, we need to make
855 * sure .release handler of kobject is run with holding the
856 * global lock
857 */
839static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) 858static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
840{ 859{
841 /* see if we live in a "glue" directory */ 860 /* see if we live in a "glue" directory */
842 if (!glue_dir || !dev->class || 861 if (!live_in_glue_dir(glue_dir, dev))
843 glue_dir->kset != &dev->class->p->glue_dirs)
844 return; 862 return;
845 863
846 mutex_lock(&gdp_mutex); 864 mutex_lock(&gdp_mutex);
@@ -848,11 +866,6 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
848 mutex_unlock(&gdp_mutex); 866 mutex_unlock(&gdp_mutex);
849} 867}
850 868
851static void cleanup_device_parent(struct device *dev)
852{
853 cleanup_glue_dir(dev, dev->kobj.parent);
854}
855
856static int device_add_class_symlinks(struct device *dev) 869static int device_add_class_symlinks(struct device *dev)
857{ 870{
858 struct device_node *of_node = dev_of_node(dev); 871 struct device_node *of_node = dev_of_node(dev);
@@ -1028,6 +1041,7 @@ int device_add(struct device *dev)
1028 struct kobject *kobj; 1041 struct kobject *kobj;
1029 struct class_interface *class_intf; 1042 struct class_interface *class_intf;
1030 int error = -EINVAL; 1043 int error = -EINVAL;
1044 struct kobject *glue_dir = NULL;
1031 1045
1032 dev = get_device(dev); 1046 dev = get_device(dev);
1033 if (!dev) 1047 if (!dev)
@@ -1072,8 +1086,10 @@ int device_add(struct device *dev)
1072 /* first, register with generic layer. */ 1086 /* first, register with generic layer. */
1073 /* we require the name to be set before, and pass NULL */ 1087 /* we require the name to be set before, and pass NULL */
1074 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); 1088 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
1075 if (error) 1089 if (error) {
1090 glue_dir = get_glue_dir(dev);
1076 goto Error; 1091 goto Error;
1092 }
1077 1093
1078 /* notify platform of device entry */ 1094 /* notify platform of device entry */
1079 if (platform_notify) 1095 if (platform_notify)
@@ -1154,9 +1170,10 @@ done:
1154 device_remove_file(dev, &dev_attr_uevent); 1170 device_remove_file(dev, &dev_attr_uevent);
1155 attrError: 1171 attrError:
1156 kobject_uevent(&dev->kobj, KOBJ_REMOVE); 1172 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
1173 glue_dir = get_glue_dir(dev);
1157 kobject_del(&dev->kobj); 1174 kobject_del(&dev->kobj);
1158 Error: 1175 Error:
1159 cleanup_device_parent(dev); 1176 cleanup_glue_dir(dev, glue_dir);
1160 put_device(parent); 1177 put_device(parent);
1161name_error: 1178name_error:
1162 kfree(dev->p); 1179 kfree(dev->p);
@@ -1232,6 +1249,7 @@ EXPORT_SYMBOL_GPL(put_device);
1232void device_del(struct device *dev) 1249void device_del(struct device *dev)
1233{ 1250{
1234 struct device *parent = dev->parent; 1251 struct device *parent = dev->parent;
1252 struct kobject *glue_dir = NULL;
1235 struct class_interface *class_intf; 1253 struct class_interface *class_intf;
1236 1254
1237 /* Notify clients of device removal. This call must come 1255 /* Notify clients of device removal. This call must come
@@ -1276,8 +1294,9 @@ void device_del(struct device *dev)
1276 blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 1294 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
1277 BUS_NOTIFY_REMOVED_DEVICE, dev); 1295 BUS_NOTIFY_REMOVED_DEVICE, dev);
1278 kobject_uevent(&dev->kobj, KOBJ_REMOVE); 1296 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
1279 cleanup_device_parent(dev); 1297 glue_dir = get_glue_dir(dev);
1280 kobject_del(&dev->kobj); 1298 kobject_del(&dev->kobj);
1299 cleanup_glue_dir(dev, glue_dir);
1281 put_device(parent); 1300 put_device(parent);
1282} 1301}
1283EXPORT_SYMBOL_GPL(device_del); 1302EXPORT_SYMBOL_GPL(device_del);