Commit 094e47e9fa79e28f0e51e37400ea6eea35a4ee1f
Committed by
Greg Kroah-Hartman
1 parent
3ce9a7c0ac
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Driver Core: don't oops with unregistered driver in driver_find_device()
driver_find_device() can be called with an unregistered driver. Need to check driver_private to see if it's populated or not, especially under deferrable probe. In the case that there are 2 drivers, one depends on the other. With -EPROBE_DEFER, two drivers can use deferred probe to ensure that their relative probe order doesn't matter. If dependee driver is probed first, then the dependant's driver_find_device('dependee') succeeds. If the dependant is probed first, then the dependant's driver_find_device('dependee') should return NULL, and the dependant should get -EPROBE_DEFER. driver_find_device() needs to return NULL if it's not populated. In [PATCHv5 2/3] ARM: tegra: Add SMMU enabler in AHB: http://article.gmane.org/gmane.linux.ports.tegra/4658 "tegra_ahb_driver" may not be populated when it's called. For more SMMU/AHB specific discussion, refer to the following thread: https://lkml.org/lkml/2012/5/10/21 Signed-off-by: Hiroshi DOYU <hdoyu@nvidia.com> Cc: Stephen Warren <swarren@wwwdotorg.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
drivers/base/driver.c
1 | /* | 1 | /* |
2 | * driver.c - centralized device driver management | 2 | * driver.c - centralized device driver management |
3 | * | 3 | * |
4 | * Copyright (c) 2002-3 Patrick Mochel | 4 | * Copyright (c) 2002-3 Patrick Mochel |
5 | * Copyright (c) 2002-3 Open Source Development Labs | 5 | * Copyright (c) 2002-3 Open Source Development Labs |
6 | * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> | 6 | * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> |
7 | * Copyright (c) 2007 Novell Inc. | 7 | * Copyright (c) 2007 Novell Inc. |
8 | * | 8 | * |
9 | * This file is released under the GPLv2 | 9 | * This file is released under the GPLv2 |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
18 | #include "base.h" | 18 | #include "base.h" |
19 | 19 | ||
20 | static struct device *next_device(struct klist_iter *i) | 20 | static struct device *next_device(struct klist_iter *i) |
21 | { | 21 | { |
22 | struct klist_node *n = klist_next(i); | 22 | struct klist_node *n = klist_next(i); |
23 | struct device *dev = NULL; | 23 | struct device *dev = NULL; |
24 | struct device_private *dev_prv; | 24 | struct device_private *dev_prv; |
25 | 25 | ||
26 | if (n) { | 26 | if (n) { |
27 | dev_prv = to_device_private_driver(n); | 27 | dev_prv = to_device_private_driver(n); |
28 | dev = dev_prv->device; | 28 | dev = dev_prv->device; |
29 | } | 29 | } |
30 | return dev; | 30 | return dev; |
31 | } | 31 | } |
32 | 32 | ||
33 | /** | 33 | /** |
34 | * driver_for_each_device - Iterator for devices bound to a driver. | 34 | * driver_for_each_device - Iterator for devices bound to a driver. |
35 | * @drv: Driver we're iterating. | 35 | * @drv: Driver we're iterating. |
36 | * @start: Device to begin with | 36 | * @start: Device to begin with |
37 | * @data: Data to pass to the callback. | 37 | * @data: Data to pass to the callback. |
38 | * @fn: Function to call for each device. | 38 | * @fn: Function to call for each device. |
39 | * | 39 | * |
40 | * Iterate over the @drv's list of devices calling @fn for each one. | 40 | * Iterate over the @drv's list of devices calling @fn for each one. |
41 | */ | 41 | */ |
42 | int driver_for_each_device(struct device_driver *drv, struct device *start, | 42 | int driver_for_each_device(struct device_driver *drv, struct device *start, |
43 | void *data, int (*fn)(struct device *, void *)) | 43 | void *data, int (*fn)(struct device *, void *)) |
44 | { | 44 | { |
45 | struct klist_iter i; | 45 | struct klist_iter i; |
46 | struct device *dev; | 46 | struct device *dev; |
47 | int error = 0; | 47 | int error = 0; |
48 | 48 | ||
49 | if (!drv) | 49 | if (!drv) |
50 | return -EINVAL; | 50 | return -EINVAL; |
51 | 51 | ||
52 | klist_iter_init_node(&drv->p->klist_devices, &i, | 52 | klist_iter_init_node(&drv->p->klist_devices, &i, |
53 | start ? &start->p->knode_driver : NULL); | 53 | start ? &start->p->knode_driver : NULL); |
54 | while ((dev = next_device(&i)) && !error) | 54 | while ((dev = next_device(&i)) && !error) |
55 | error = fn(dev, data); | 55 | error = fn(dev, data); |
56 | klist_iter_exit(&i); | 56 | klist_iter_exit(&i); |
57 | return error; | 57 | return error; |
58 | } | 58 | } |
59 | EXPORT_SYMBOL_GPL(driver_for_each_device); | 59 | EXPORT_SYMBOL_GPL(driver_for_each_device); |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * driver_find_device - device iterator for locating a particular device. | 62 | * driver_find_device - device iterator for locating a particular device. |
63 | * @drv: The device's driver | 63 | * @drv: The device's driver |
64 | * @start: Device to begin with | 64 | * @start: Device to begin with |
65 | * @data: Data to pass to match function | 65 | * @data: Data to pass to match function |
66 | * @match: Callback function to check device | 66 | * @match: Callback function to check device |
67 | * | 67 | * |
68 | * This is similar to the driver_for_each_device() function above, but | 68 | * This is similar to the driver_for_each_device() function above, but |
69 | * it returns a reference to a device that is 'found' for later use, as | 69 | * it returns a reference to a device that is 'found' for later use, as |
70 | * determined by the @match callback. | 70 | * determined by the @match callback. |
71 | * | 71 | * |
72 | * The callback should return 0 if the device doesn't match and non-zero | 72 | * The callback should return 0 if the device doesn't match and non-zero |
73 | * if it does. If the callback returns non-zero, this function will | 73 | * if it does. If the callback returns non-zero, this function will |
74 | * return to the caller and not iterate over any more devices. | 74 | * return to the caller and not iterate over any more devices. |
75 | */ | 75 | */ |
76 | struct device *driver_find_device(struct device_driver *drv, | 76 | struct device *driver_find_device(struct device_driver *drv, |
77 | struct device *start, void *data, | 77 | struct device *start, void *data, |
78 | int (*match)(struct device *dev, void *data)) | 78 | int (*match)(struct device *dev, void *data)) |
79 | { | 79 | { |
80 | struct klist_iter i; | 80 | struct klist_iter i; |
81 | struct device *dev; | 81 | struct device *dev; |
82 | 82 | ||
83 | if (!drv) | 83 | if (!drv || !drv->p) |
84 | return NULL; | 84 | return NULL; |
85 | 85 | ||
86 | klist_iter_init_node(&drv->p->klist_devices, &i, | 86 | klist_iter_init_node(&drv->p->klist_devices, &i, |
87 | (start ? &start->p->knode_driver : NULL)); | 87 | (start ? &start->p->knode_driver : NULL)); |
88 | while ((dev = next_device(&i))) | 88 | while ((dev = next_device(&i))) |
89 | if (match(dev, data) && get_device(dev)) | 89 | if (match(dev, data) && get_device(dev)) |
90 | break; | 90 | break; |
91 | klist_iter_exit(&i); | 91 | klist_iter_exit(&i); |
92 | return dev; | 92 | return dev; |
93 | } | 93 | } |
94 | EXPORT_SYMBOL_GPL(driver_find_device); | 94 | EXPORT_SYMBOL_GPL(driver_find_device); |
95 | 95 | ||
96 | /** | 96 | /** |
97 | * driver_create_file - create sysfs file for driver. | 97 | * driver_create_file - create sysfs file for driver. |
98 | * @drv: driver. | 98 | * @drv: driver. |
99 | * @attr: driver attribute descriptor. | 99 | * @attr: driver attribute descriptor. |
100 | */ | 100 | */ |
101 | int driver_create_file(struct device_driver *drv, | 101 | int driver_create_file(struct device_driver *drv, |
102 | const struct driver_attribute *attr) | 102 | const struct driver_attribute *attr) |
103 | { | 103 | { |
104 | int error; | 104 | int error; |
105 | if (drv) | 105 | if (drv) |
106 | error = sysfs_create_file(&drv->p->kobj, &attr->attr); | 106 | error = sysfs_create_file(&drv->p->kobj, &attr->attr); |
107 | else | 107 | else |
108 | error = -EINVAL; | 108 | error = -EINVAL; |
109 | return error; | 109 | return error; |
110 | } | 110 | } |
111 | EXPORT_SYMBOL_GPL(driver_create_file); | 111 | EXPORT_SYMBOL_GPL(driver_create_file); |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * driver_remove_file - remove sysfs file for driver. | 114 | * driver_remove_file - remove sysfs file for driver. |
115 | * @drv: driver. | 115 | * @drv: driver. |
116 | * @attr: driver attribute descriptor. | 116 | * @attr: driver attribute descriptor. |
117 | */ | 117 | */ |
118 | void driver_remove_file(struct device_driver *drv, | 118 | void driver_remove_file(struct device_driver *drv, |
119 | const struct driver_attribute *attr) | 119 | const struct driver_attribute *attr) |
120 | { | 120 | { |
121 | if (drv) | 121 | if (drv) |
122 | sysfs_remove_file(&drv->p->kobj, &attr->attr); | 122 | sysfs_remove_file(&drv->p->kobj, &attr->attr); |
123 | } | 123 | } |
124 | EXPORT_SYMBOL_GPL(driver_remove_file); | 124 | EXPORT_SYMBOL_GPL(driver_remove_file); |
125 | 125 | ||
126 | static int driver_add_groups(struct device_driver *drv, | 126 | static int driver_add_groups(struct device_driver *drv, |
127 | const struct attribute_group **groups) | 127 | const struct attribute_group **groups) |
128 | { | 128 | { |
129 | int error = 0; | 129 | int error = 0; |
130 | int i; | 130 | int i; |
131 | 131 | ||
132 | if (groups) { | 132 | if (groups) { |
133 | for (i = 0; groups[i]; i++) { | 133 | for (i = 0; groups[i]; i++) { |
134 | error = sysfs_create_group(&drv->p->kobj, groups[i]); | 134 | error = sysfs_create_group(&drv->p->kobj, groups[i]); |
135 | if (error) { | 135 | if (error) { |
136 | while (--i >= 0) | 136 | while (--i >= 0) |
137 | sysfs_remove_group(&drv->p->kobj, | 137 | sysfs_remove_group(&drv->p->kobj, |
138 | groups[i]); | 138 | groups[i]); |
139 | break; | 139 | break; |
140 | } | 140 | } |
141 | } | 141 | } |
142 | } | 142 | } |
143 | return error; | 143 | return error; |
144 | } | 144 | } |
145 | 145 | ||
146 | static void driver_remove_groups(struct device_driver *drv, | 146 | static void driver_remove_groups(struct device_driver *drv, |
147 | const struct attribute_group **groups) | 147 | const struct attribute_group **groups) |
148 | { | 148 | { |
149 | int i; | 149 | int i; |
150 | 150 | ||
151 | if (groups) | 151 | if (groups) |
152 | for (i = 0; groups[i]; i++) | 152 | for (i = 0; groups[i]; i++) |
153 | sysfs_remove_group(&drv->p->kobj, groups[i]); | 153 | sysfs_remove_group(&drv->p->kobj, groups[i]); |
154 | } | 154 | } |
155 | 155 | ||
156 | /** | 156 | /** |
157 | * driver_register - register driver with bus | 157 | * driver_register - register driver with bus |
158 | * @drv: driver to register | 158 | * @drv: driver to register |
159 | * | 159 | * |
160 | * We pass off most of the work to the bus_add_driver() call, | 160 | * We pass off most of the work to the bus_add_driver() call, |
161 | * since most of the things we have to do deal with the bus | 161 | * since most of the things we have to do deal with the bus |
162 | * structures. | 162 | * structures. |
163 | */ | 163 | */ |
164 | int driver_register(struct device_driver *drv) | 164 | int driver_register(struct device_driver *drv) |
165 | { | 165 | { |
166 | int ret; | 166 | int ret; |
167 | struct device_driver *other; | 167 | struct device_driver *other; |
168 | 168 | ||
169 | BUG_ON(!drv->bus->p); | 169 | BUG_ON(!drv->bus->p); |
170 | 170 | ||
171 | if ((drv->bus->probe && drv->probe) || | 171 | if ((drv->bus->probe && drv->probe) || |
172 | (drv->bus->remove && drv->remove) || | 172 | (drv->bus->remove && drv->remove) || |
173 | (drv->bus->shutdown && drv->shutdown)) | 173 | (drv->bus->shutdown && drv->shutdown)) |
174 | printk(KERN_WARNING "Driver '%s' needs updating - please use " | 174 | printk(KERN_WARNING "Driver '%s' needs updating - please use " |
175 | "bus_type methods\n", drv->name); | 175 | "bus_type methods\n", drv->name); |
176 | 176 | ||
177 | other = driver_find(drv->name, drv->bus); | 177 | other = driver_find(drv->name, drv->bus); |
178 | if (other) { | 178 | if (other) { |
179 | printk(KERN_ERR "Error: Driver '%s' is already registered, " | 179 | printk(KERN_ERR "Error: Driver '%s' is already registered, " |
180 | "aborting...\n", drv->name); | 180 | "aborting...\n", drv->name); |
181 | return -EBUSY; | 181 | return -EBUSY; |
182 | } | 182 | } |
183 | 183 | ||
184 | ret = bus_add_driver(drv); | 184 | ret = bus_add_driver(drv); |
185 | if (ret) | 185 | if (ret) |
186 | return ret; | 186 | return ret; |
187 | ret = driver_add_groups(drv, drv->groups); | 187 | ret = driver_add_groups(drv, drv->groups); |
188 | if (ret) | 188 | if (ret) |
189 | bus_remove_driver(drv); | 189 | bus_remove_driver(drv); |
190 | return ret; | 190 | return ret; |
191 | } | 191 | } |
192 | EXPORT_SYMBOL_GPL(driver_register); | 192 | EXPORT_SYMBOL_GPL(driver_register); |
193 | 193 | ||
194 | /** | 194 | /** |
195 | * driver_unregister - remove driver from system. | 195 | * driver_unregister - remove driver from system. |
196 | * @drv: driver. | 196 | * @drv: driver. |
197 | * | 197 | * |
198 | * Again, we pass off most of the work to the bus-level call. | 198 | * Again, we pass off most of the work to the bus-level call. |
199 | */ | 199 | */ |
200 | void driver_unregister(struct device_driver *drv) | 200 | void driver_unregister(struct device_driver *drv) |
201 | { | 201 | { |
202 | if (!drv || !drv->p) { | 202 | if (!drv || !drv->p) { |
203 | WARN(1, "Unexpected driver unregister!\n"); | 203 | WARN(1, "Unexpected driver unregister!\n"); |
204 | return; | 204 | return; |
205 | } | 205 | } |
206 | driver_remove_groups(drv, drv->groups); | 206 | driver_remove_groups(drv, drv->groups); |
207 | bus_remove_driver(drv); | 207 | bus_remove_driver(drv); |
208 | } | 208 | } |
209 | EXPORT_SYMBOL_GPL(driver_unregister); | 209 | EXPORT_SYMBOL_GPL(driver_unregister); |
210 | 210 | ||
211 | /** | 211 | /** |
212 | * driver_find - locate driver on a bus by its name. | 212 | * driver_find - locate driver on a bus by its name. |
213 | * @name: name of the driver. | 213 | * @name: name of the driver. |
214 | * @bus: bus to scan for the driver. | 214 | * @bus: bus to scan for the driver. |
215 | * | 215 | * |
216 | * Call kset_find_obj() to iterate over list of drivers on | 216 | * Call kset_find_obj() to iterate over list of drivers on |
217 | * a bus to find driver by name. Return driver if found. | 217 | * a bus to find driver by name. Return driver if found. |
218 | * | 218 | * |
219 | * This routine provides no locking to prevent the driver it returns | 219 | * This routine provides no locking to prevent the driver it returns |
220 | * from being unregistered or unloaded while the caller is using it. | 220 | * from being unregistered or unloaded while the caller is using it. |
221 | * The caller is responsible for preventing this. | 221 | * The caller is responsible for preventing this. |
222 | */ | 222 | */ |
223 | struct device_driver *driver_find(const char *name, struct bus_type *bus) | 223 | struct device_driver *driver_find(const char *name, struct bus_type *bus) |
224 | { | 224 | { |
225 | struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); | 225 | struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); |
226 | struct driver_private *priv; | 226 | struct driver_private *priv; |
227 | 227 | ||
228 | if (k) { | 228 | if (k) { |
229 | /* Drop reference added by kset_find_obj() */ | 229 | /* Drop reference added by kset_find_obj() */ |
230 | kobject_put(k); | 230 | kobject_put(k); |
231 | priv = to_driver(k); | 231 | priv = to_driver(k); |
232 | return priv->driver; | 232 | return priv->driver; |
233 | } | 233 | } |
234 | return NULL; | 234 | return NULL; |
235 | } | 235 | } |
236 | EXPORT_SYMBOL_GPL(driver_find); | 236 | EXPORT_SYMBOL_GPL(driver_find); |
237 | 237 |