diff options
author | Ming Lei <ming.lei@canonical.com> | 2016-07-10 07:27:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-08-31 09:13:55 -0400 |
commit | cebf8fd16900fdfd58c0028617944f808f97fe50 (patch) | |
tree | b4042d299494ce09ce38e37186191456fd0dfa2b /drivers/base/core.c | |
parent | 24ef5f360f22e4408cb49d75755d27d5a21820f7 (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.c | 39 |
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 | ||
839 | static 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 | |||
848 | static 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 | */ | ||
839 | static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) | 858 | static 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 | ||
851 | static void cleanup_device_parent(struct device *dev) | ||
852 | { | ||
853 | cleanup_glue_dir(dev, dev->kobj.parent); | ||
854 | } | ||
855 | |||
856 | static int device_add_class_symlinks(struct device *dev) | 869 | static 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); |
1161 | name_error: | 1178 | name_error: |
1162 | kfree(dev->p); | 1179 | kfree(dev->p); |
@@ -1232,6 +1249,7 @@ EXPORT_SYMBOL_GPL(put_device); | |||
1232 | void device_del(struct device *dev) | 1249 | void 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 | } |
1283 | EXPORT_SYMBOL_GPL(device_del); | 1302 | EXPORT_SYMBOL_GPL(device_del); |