diff options
author | Douglas Thompson <dougthompson@xmission.com> | 2007-07-19 04:50:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:57 -0400 |
commit | 1c3631ff1f805cb72644fcde02b7c58950f21cd5 (patch) | |
tree | 2d0f8867f21cf2dedb7d94a262028898333583f4 /drivers | |
parent | 8096cfafbb7ad3cb1a286ae7e8086167f4ebb4b6 (diff) |
drivers/edac: fix edac_device sysfs completion code
With feedback, this patch corrects operation of the kobject release operation
on kobjects, attributes and controls for the edac_device.
Cc: Alan Cox alan@lxorguk.ukuu.org.uk
Signed-off-by: Doug Thompson <dougthompson@xmission.com>
Acked-by: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/edac/edac_core.h | 10 | ||||
-rw-r--r-- | drivers/edac/edac_device.c | 37 | ||||
-rw-r--r-- | drivers/edac/edac_device_sysfs.c | 341 | ||||
-rw-r--r-- | drivers/edac/edac_module.h | 4 |
4 files changed, 277 insertions, 115 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index bd7f00cf2443..4e31ac438760 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h | |||
@@ -337,6 +337,9 @@ struct mcidev_sysfs_attribute { | |||
337 | */ | 337 | */ |
338 | struct mem_ctl_info { | 338 | struct mem_ctl_info { |
339 | struct list_head link; /* for global list of mem_ctl_info structs */ | 339 | struct list_head link; /* for global list of mem_ctl_info structs */ |
340 | |||
341 | struct module *owner; /* Module owner of this control struct */ | ||
342 | |||
340 | unsigned long mtype_cap; /* memory types supported by mc */ | 343 | unsigned long mtype_cap; /* memory types supported by mc */ |
341 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ | 344 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ |
342 | unsigned long edac_cap; /* configuration capabilities - this is | 345 | unsigned long edac_cap; /* configuration capabilities - this is |
@@ -510,7 +513,6 @@ struct edac_device_block { | |||
510 | 513 | ||
511 | /* edac sysfs device control */ | 514 | /* edac sysfs device control */ |
512 | struct kobject kobj; | 515 | struct kobject kobj; |
513 | struct completion kobj_complete; | ||
514 | }; | 516 | }; |
515 | 517 | ||
516 | /* device instance control structure */ | 518 | /* device instance control structure */ |
@@ -525,7 +527,6 @@ struct edac_device_instance { | |||
525 | 527 | ||
526 | /* edac sysfs device control */ | 528 | /* edac sysfs device control */ |
527 | struct kobject kobj; | 529 | struct kobject kobj; |
528 | struct completion kobj_complete; | ||
529 | }; | 530 | }; |
530 | 531 | ||
531 | 532 | ||
@@ -537,6 +538,8 @@ struct edac_device_ctl_info { | |||
537 | /* for global list of edac_device_ctl_info structs */ | 538 | /* for global list of edac_device_ctl_info structs */ |
538 | struct list_head link; | 539 | struct list_head link; |
539 | 540 | ||
541 | struct module *owner; /* Module owner of this control struct */ | ||
542 | |||
540 | int dev_idx; | 543 | int dev_idx; |
541 | 544 | ||
542 | /* Per instance controls for this edac_device */ | 545 | /* Per instance controls for this edac_device */ |
@@ -587,7 +590,7 @@ struct edac_device_ctl_info { | |||
587 | * NMI handlers may be traversing list | 590 | * NMI handlers may be traversing list |
588 | */ | 591 | */ |
589 | struct rcu_head rcu; | 592 | struct rcu_head rcu; |
590 | struct completion complete; | 593 | struct completion removal_complete; |
591 | 594 | ||
592 | /* sysfs top name under 'edac' directory | 595 | /* sysfs top name under 'edac' directory |
593 | * and instance name: | 596 | * and instance name: |
@@ -611,7 +614,6 @@ struct edac_device_ctl_info { | |||
611 | * device this structure controls | 614 | * device this structure controls |
612 | */ | 615 | */ |
613 | struct kobject kobj; | 616 | struct kobject kobj; |
614 | struct completion kobj_complete; | ||
615 | }; | 617 | }; |
616 | 618 | ||
617 | /* To get from the instance's wq to the beginning of the ctl structure */ | 619 | /* To get from the instance's wq to the beginning of the ctl structure */ |
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 6020da68cbef..173f4ba0f7c8 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c | |||
@@ -48,6 +48,7 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) | |||
48 | } | 48 | } |
49 | #endif /* CONFIG_EDAC_DEBUG */ | 49 | #endif /* CONFIG_EDAC_DEBUG */ |
50 | 50 | ||
51 | |||
51 | /* | 52 | /* |
52 | * edac_device_alloc_ctl_info() | 53 | * edac_device_alloc_ctl_info() |
53 | * Allocate a new edac device control info structure | 54 | * Allocate a new edac device control info structure |
@@ -78,6 +79,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( | |||
78 | unsigned count; | 79 | unsigned count; |
79 | unsigned instance, block, attr; | 80 | unsigned instance, block, attr; |
80 | void *pvt; | 81 | void *pvt; |
82 | int err; | ||
81 | 83 | ||
82 | debugf1("%s() instances=%d blocks=%d\n", | 84 | debugf1("%s() instances=%d blocks=%d\n", |
83 | __func__, nr_instances, nr_blocks); | 85 | __func__, nr_instances, nr_blocks); |
@@ -208,6 +210,22 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( | |||
208 | /* Mark this instance as merely ALLOCATED */ | 210 | /* Mark this instance as merely ALLOCATED */ |
209 | dev_ctl->op_state = OP_ALLOC; | 211 | dev_ctl->op_state = OP_ALLOC; |
210 | 212 | ||
213 | /* | ||
214 | * Initialize the 'root' kobj for the edac_device controller | ||
215 | */ | ||
216 | err = edac_device_register_sysfs_main_kobj(dev_ctl); | ||
217 | if (err) { | ||
218 | kfree(dev_ctl); | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | /* at this point, the root kobj is valid, and in order to | ||
223 | * 'free' the object, then the function: | ||
224 | * edac_device_unregister_sysfs_main_kobj() must be called | ||
225 | * which will perform kobj unregistration and the actual free | ||
226 | * will occur during the kobject callback operation | ||
227 | */ | ||
228 | |||
211 | return dev_ctl; | 229 | return dev_ctl; |
212 | } | 230 | } |
213 | EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); | 231 | EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); |
@@ -219,7 +237,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); | |||
219 | */ | 237 | */ |
220 | void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) | 238 | void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) |
221 | { | 239 | { |
222 | kfree(ctl_info); | 240 | edac_device_unregister_sysfs_main_kobj(ctl_info); |
223 | } | 241 | } |
224 | EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); | 242 | EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); |
225 | 243 | ||
@@ -315,22 +333,23 @@ static void complete_edac_device_list_del(struct rcu_head *head) | |||
315 | 333 | ||
316 | edac_dev = container_of(head, struct edac_device_ctl_info, rcu); | 334 | edac_dev = container_of(head, struct edac_device_ctl_info, rcu); |
317 | INIT_LIST_HEAD(&edac_dev->link); | 335 | INIT_LIST_HEAD(&edac_dev->link); |
318 | complete(&edac_dev->complete); | 336 | complete(&edac_dev->removal_complete); |
319 | } | 337 | } |
320 | 338 | ||
321 | /* | 339 | /* |
322 | * del_edac_device_from_global_list | 340 | * del_edac_device_from_global_list |
323 | * | 341 | * |
324 | * remove the RCU, setup for a callback call, then wait for the | 342 | * remove the RCU, setup for a callback call, |
325 | * callback to occur | 343 | * then wait for the callback to occur |
326 | */ | 344 | */ |
327 | static void del_edac_device_from_global_list(struct edac_device_ctl_info | 345 | static void del_edac_device_from_global_list(struct edac_device_ctl_info |
328 | *edac_device) | 346 | *edac_device) |
329 | { | 347 | { |
330 | list_del_rcu(&edac_device->link); | 348 | list_del_rcu(&edac_device->link); |
331 | init_completion(&edac_device->complete); | 349 | |
350 | init_completion(&edac_device->removal_complete); | ||
332 | call_rcu(&edac_device->rcu, complete_edac_device_list_del); | 351 | call_rcu(&edac_device->rcu, complete_edac_device_list_del); |
333 | wait_for_completion(&edac_device->complete); | 352 | wait_for_completion(&edac_device->removal_complete); |
334 | } | 353 | } |
335 | 354 | ||
336 | /** | 355 | /** |
@@ -542,14 +561,14 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev) | |||
542 | /* clear workq processing on this instance */ | 561 | /* clear workq processing on this instance */ |
543 | edac_device_workq_teardown(edac_dev); | 562 | edac_device_workq_teardown(edac_dev); |
544 | 563 | ||
545 | /* Tear down the sysfs entries for this instance */ | ||
546 | edac_device_remove_sysfs(edac_dev); | ||
547 | |||
548 | /* deregister from global list */ | 564 | /* deregister from global list */ |
549 | del_edac_device_from_global_list(edac_dev); | 565 | del_edac_device_from_global_list(edac_dev); |
550 | 566 | ||
551 | mutex_unlock(&device_ctls_mutex); | 567 | mutex_unlock(&device_ctls_mutex); |
552 | 568 | ||
569 | /* Tear down the sysfs entries for this instance */ | ||
570 | edac_device_remove_sysfs(edac_dev); | ||
571 | |||
553 | edac_printk(KERN_INFO, EDAC_MC, | 572 | edac_printk(KERN_INFO, EDAC_MC, |
554 | "Removed device %d for %s %s: DEV %s\n", | 573 | "Removed device %d for %s %s: DEV %s\n", |
555 | edac_dev->dev_idx, | 574 | edac_dev->dev_idx, |
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 235b4c79355d..52769ae69bd2 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * file for managing the edac_device class of devices for EDAC | 2 | * file for managing the edac_device class of devices for EDAC |
3 | * | 3 | * |
4 | * (C) 2007 SoftwareBitMaker(http://www.softwarebitmaker.com) | 4 | * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com) |
5 | * | ||
5 | * This file may be distributed under the terms of the | 6 | * This file may be distributed under the terms of the |
6 | * GNU General Public License. | 7 | * GNU General Public License. |
7 | * | 8 | * |
@@ -10,6 +11,7 @@ | |||
10 | */ | 11 | */ |
11 | 12 | ||
12 | #include <linux/ctype.h> | 13 | #include <linux/ctype.h> |
14 | #include <linux/module.h> | ||
13 | 15 | ||
14 | #include "edac_core.h" | 16 | #include "edac_core.h" |
15 | #include "edac_module.h" | 17 | #include "edac_module.h" |
@@ -19,7 +21,6 @@ | |||
19 | #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj) | 21 | #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj) |
20 | #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr) | 22 | #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr) |
21 | 23 | ||
22 | /************************** edac_device sysfs code and data **************/ | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Set of edac_device_ctl_info attribute store/show functions | 26 | * Set of edac_device_ctl_info attribute store/show functions |
@@ -103,8 +104,8 @@ static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info | |||
103 | /* edac_device_ctl_info specific attribute structure */ | 104 | /* edac_device_ctl_info specific attribute structure */ |
104 | struct ctl_info_attribute { | 105 | struct ctl_info_attribute { |
105 | struct attribute attr; | 106 | struct attribute attr; |
106 | ssize_t(*show) (struct edac_device_ctl_info *, char *); | 107 | ssize_t(*show) (struct edac_device_ctl_info *, char *); |
107 | ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t); | 108 | ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t); |
108 | }; | 109 | }; |
109 | 110 | ||
110 | #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj) | 111 | #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj) |
@@ -168,45 +169,76 @@ static struct ctl_info_attribute *device_ctrl_attr[] = { | |||
168 | NULL, | 169 | NULL, |
169 | }; | 170 | }; |
170 | 171 | ||
171 | /* Main DEVICE kobject release() function */ | 172 | /* |
173 | * edac_device_ctrl_master_release | ||
174 | * | ||
175 | * called when the reference count for the 'main' kobj | ||
176 | * for a edac_device control struct reaches zero | ||
177 | * | ||
178 | * Reference count model: | ||
179 | * One 'main' kobject for each control structure allocated. | ||
180 | * That main kobj is initially set to one AND | ||
181 | * the reference count for the EDAC 'core' module is | ||
182 | * bumped by one, thus added 'keep in memory' dependency. | ||
183 | * | ||
184 | * Each new internal kobj (in instances and blocks) then | ||
185 | * bumps the 'main' kobject. | ||
186 | * | ||
187 | * When they are released their release functions decrement | ||
188 | * the 'main' kobj. | ||
189 | * | ||
190 | * When the main kobj reaches zero (0) then THIS function | ||
191 | * is called which then decrements the EDAC 'core' module. | ||
192 | * When the module reference count reaches zero then the | ||
193 | * module no longer has dependency on keeping the release | ||
194 | * function code in memory and module can be unloaded. | ||
195 | * | ||
196 | * This will support several control objects as well, each | ||
197 | * with its own 'main' kobj. | ||
198 | */ | ||
172 | static void edac_device_ctrl_master_release(struct kobject *kobj) | 199 | static void edac_device_ctrl_master_release(struct kobject *kobj) |
173 | { | 200 | { |
174 | struct edac_device_ctl_info *edac_dev; | 201 | struct edac_device_ctl_info *edac_dev = to_edacdev(kobj); |
175 | 202 | ||
176 | edac_dev = to_edacdev(kobj); | 203 | debugf1("%s() control index=%d\n", __func__, edac_dev->dev_idx); |
177 | 204 | ||
178 | debugf1("%s()\n", __func__); | 205 | /* decrement the EDAC CORE module ref count */ |
179 | complete(&edac_dev->kobj_complete); | 206 | module_put(edac_dev->owner); |
207 | |||
208 | /* free the control struct containing the 'main' kobj | ||
209 | * passed in to this routine | ||
210 | */ | ||
211 | kfree(edac_dev); | ||
180 | } | 212 | } |
181 | 213 | ||
214 | /* ktype for the main (master) kobject */ | ||
182 | static struct kobj_type ktype_device_ctrl = { | 215 | static struct kobj_type ktype_device_ctrl = { |
183 | .release = edac_device_ctrl_master_release, | 216 | .release = edac_device_ctrl_master_release, |
184 | .sysfs_ops = &device_ctl_info_ops, | 217 | .sysfs_ops = &device_ctl_info_ops, |
185 | .default_attrs = (struct attribute **)device_ctrl_attr, | 218 | .default_attrs = (struct attribute **)device_ctrl_attr, |
186 | }; | 219 | }; |
187 | 220 | ||
188 | /**************** edac_device main kobj ctor/dtor code *********************/ | ||
189 | |||
190 | /* | 221 | /* |
191 | * edac_device_register_main_kobj | 222 | * edac_device_register_sysfs_main_kobj |
192 | * | 223 | * |
193 | * perform the high level setup for the new edac_device instance | 224 | * perform the high level setup for the new edac_device instance |
194 | * | 225 | * |
195 | * Return: 0 SUCCESS | 226 | * Return: 0 SUCCESS |
196 | * !0 FAILURE | 227 | * !0 FAILURE |
197 | */ | 228 | */ |
198 | static int edac_device_register_main_kobj(struct edac_device_ctl_info *edac_dev) | 229 | int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) |
199 | { | 230 | { |
200 | int err = 0; | ||
201 | struct sysdev_class *edac_class; | 231 | struct sysdev_class *edac_class; |
232 | int err; | ||
202 | 233 | ||
203 | debugf1("%s()\n", __func__); | 234 | debugf1("%s()\n", __func__); |
204 | 235 | ||
205 | /* get the /sys/devices/system/edac reference */ | 236 | /* get the /sys/devices/system/edac reference */ |
206 | edac_class = edac_get_edac_class(); | 237 | edac_class = edac_get_edac_class(); |
207 | if (edac_class == NULL) { | 238 | if (edac_class == NULL) { |
208 | debugf1("%s() no edac_class error=%d\n", __func__, err); | 239 | debugf1("%s() no edac_class error\n", __func__); |
209 | return err; | 240 | err = -ENODEV; |
241 | goto err_out; | ||
210 | } | 242 | } |
211 | 243 | ||
212 | /* Point to the 'edac_class' this instance 'reports' to */ | 244 | /* Point to the 'edac_class' this instance 'reports' to */ |
@@ -223,42 +255,65 @@ static int edac_device_register_main_kobj(struct edac_device_ctl_info *edac_dev) | |||
223 | debugf1("%s() set name of kobject to: %s\n", __func__, edac_dev->name); | 255 | debugf1("%s() set name of kobject to: %s\n", __func__, edac_dev->name); |
224 | err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); | 256 | err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); |
225 | if (err) | 257 | if (err) |
226 | return err; | 258 | goto err_out; |
259 | |||
260 | /* Record which module 'owns' this control structure | ||
261 | * and bump the ref count of the module | ||
262 | */ | ||
263 | edac_dev->owner = THIS_MODULE; | ||
264 | |||
265 | if (!try_module_get(edac_dev->owner)) { | ||
266 | err = -ENODEV; | ||
267 | goto err_out; | ||
268 | } | ||
269 | |||
270 | /* register */ | ||
227 | err = kobject_register(&edac_dev->kobj); | 271 | err = kobject_register(&edac_dev->kobj); |
228 | if (err) { | 272 | if (err) { |
229 | debugf1("%s()Failed to register '.../edac/%s'\n", | 273 | debugf1("%s()Failed to register '.../edac/%s'\n", |
230 | __func__, edac_dev->name); | 274 | __func__, edac_dev->name); |
231 | return err; | 275 | goto err_kobj_reg; |
232 | } | 276 | } |
233 | 277 | ||
278 | /* At this point, to 'free' the control struct, | ||
279 | * edac_device_unregister_sysfs_main_kobj() must be used | ||
280 | */ | ||
281 | |||
234 | debugf1("%s() Registered '.../edac/%s' kobject\n", | 282 | debugf1("%s() Registered '.../edac/%s' kobject\n", |
235 | __func__, edac_dev->name); | 283 | __func__, edac_dev->name); |
236 | 284 | ||
237 | return 0; | 285 | return 0; |
286 | |||
287 | /* Error exit stack */ | ||
288 | err_kobj_reg: | ||
289 | module_put(edac_dev->owner); | ||
290 | |||
291 | err_out: | ||
292 | return err; | ||
238 | } | 293 | } |
239 | 294 | ||
240 | /* | 295 | /* |
241 | * edac_device_unregister_main_kobj: | 296 | * edac_device_unregister_sysfs_main_kobj: |
242 | * the '..../edac/<name>' kobject | 297 | * the '..../edac/<name>' kobject |
243 | */ | 298 | */ |
244 | static void edac_device_unregister_main_kobj(struct edac_device_ctl_info | 299 | void edac_device_unregister_sysfs_main_kobj( |
245 | *edac_dev) | 300 | struct edac_device_ctl_info *edac_dev) |
246 | { | 301 | { |
247 | debugf0("%s()\n", __func__); | 302 | debugf0("%s()\n", __func__); |
248 | debugf1("%s() name of kobject is: %s\n", | 303 | debugf1("%s() name of kobject is: %s\n", |
249 | __func__, kobject_name(&edac_dev->kobj)); | 304 | __func__, kobject_name(&edac_dev->kobj)); |
250 | 305 | ||
251 | init_completion(&edac_dev->kobj_complete); | ||
252 | |||
253 | /* | 306 | /* |
254 | * Unregister the edac device's kobject and | 307 | * Unregister the edac device's kobject and |
255 | * wait for reference count to reach 0. | 308 | * allow for reference count to reach 0 at which point |
309 | * the callback will be called to: | ||
310 | * a) module_put() this module | ||
311 | * b) 'kfree' the memory | ||
256 | */ | 312 | */ |
257 | kobject_unregister(&edac_dev->kobj); | 313 | kobject_unregister(&edac_dev->kobj); |
258 | wait_for_completion(&edac_dev->kobj_complete); | ||
259 | } | 314 | } |
260 | 315 | ||
261 | /*************** edac_dev -> instance information ***********/ | 316 | /* edac_dev -> instance information */ |
262 | 317 | ||
263 | /* | 318 | /* |
264 | * Set of low-level instance attribute show functions | 319 | * Set of low-level instance attribute show functions |
@@ -285,8 +340,11 @@ static void edac_device_ctrl_instance_release(struct kobject *kobj) | |||
285 | 340 | ||
286 | debugf1("%s()\n", __func__); | 341 | debugf1("%s()\n", __func__); |
287 | 342 | ||
343 | /* map from this kobj to the main control struct | ||
344 | * and then dec the main kobj count | ||
345 | */ | ||
288 | instance = to_instance(kobj); | 346 | instance = to_instance(kobj); |
289 | complete(&instance->kobj_complete); | 347 | kobject_put(&instance->ctl->kobj); |
290 | } | 348 | } |
291 | 349 | ||
292 | /* instance specific attribute structure */ | 350 | /* instance specific attribute structure */ |
@@ -356,7 +414,7 @@ static struct kobj_type ktype_instance_ctrl = { | |||
356 | .default_attrs = (struct attribute **)device_instance_attr, | 414 | .default_attrs = (struct attribute **)device_instance_attr, |
357 | }; | 415 | }; |
358 | 416 | ||
359 | /*************** edac_dev -> instance -> block information *********/ | 417 | /* edac_dev -> instance -> block information */ |
360 | 418 | ||
361 | /* | 419 | /* |
362 | * Set of low-level block attribute show functions | 420 | * Set of low-level block attribute show functions |
@@ -381,8 +439,13 @@ static void edac_device_ctrl_block_release(struct kobject *kobj) | |||
381 | 439 | ||
382 | debugf1("%s()\n", __func__); | 440 | debugf1("%s()\n", __func__); |
383 | 441 | ||
442 | /* get the container of the kobj */ | ||
384 | block = to_block(kobj); | 443 | block = to_block(kobj); |
385 | complete(&block->kobj_complete); | 444 | |
445 | /* map from 'block kobj' to 'block->instance->controller->main_kobj' | ||
446 | * now 'release' the block kobject | ||
447 | */ | ||
448 | kobject_put(&block->instance->ctl->kobj); | ||
386 | } | 449 | } |
387 | 450 | ||
388 | /* block specific attribute structure */ | 451 | /* block specific attribute structure */ |
@@ -447,49 +510,60 @@ static struct kobj_type ktype_block_ctrl = { | |||
447 | .default_attrs = (struct attribute **)device_block_attr, | 510 | .default_attrs = (struct attribute **)device_block_attr, |
448 | }; | 511 | }; |
449 | 512 | ||
450 | /************** block ctor/dtor code ************/ | 513 | /* block ctor/dtor code */ |
451 | 514 | ||
452 | /* | 515 | /* |
453 | * edac_device_create_block | 516 | * edac_device_create_block |
454 | */ | 517 | */ |
455 | static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, | 518 | static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, |
456 | struct edac_device_instance *instance, | 519 | struct edac_device_instance *instance, |
457 | int idx) | 520 | struct edac_device_block *block) |
458 | { | 521 | { |
459 | int i; | 522 | int i; |
460 | int err; | 523 | int err; |
461 | struct edac_device_block *block; | ||
462 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; | 524 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; |
525 | struct kobject *main_kobj; | ||
463 | 526 | ||
464 | block = &instance->blocks[idx]; | 527 | debugf1("%s() Instance '%s' block '%s'\n", |
465 | 528 | __func__, instance->name, block->name); | |
466 | debugf1("%s() Instance '%s' block[%d] '%s'\n", | ||
467 | __func__, instance->name, idx, block->name); | ||
468 | 529 | ||
469 | /* init this block's kobject */ | 530 | /* init this block's kobject */ |
470 | memset(&block->kobj, 0, sizeof(struct kobject)); | 531 | memset(&block->kobj, 0, sizeof(struct kobject)); |
471 | block->kobj.parent = &instance->kobj; | 532 | block->kobj.parent = &instance->kobj; |
472 | block->kobj.ktype = &ktype_block_ctrl; | 533 | block->kobj.ktype = &ktype_block_ctrl; |
534 | block->instance = instance; | ||
473 | 535 | ||
474 | err = kobject_set_name(&block->kobj, "%s", block->name); | 536 | err = kobject_set_name(&block->kobj, "%s", block->name); |
475 | if (err) | 537 | if (err) |
476 | return err; | 538 | return err; |
477 | 539 | ||
540 | /* bump the main kobject's reference count for this controller | ||
541 | * and this instance is dependant on the main | ||
542 | */ | ||
543 | main_kobj = kobject_get(&edac_dev->kobj); | ||
544 | if (!main_kobj) { | ||
545 | err = -ENODEV; | ||
546 | goto err_out; | ||
547 | } | ||
548 | |||
549 | /* Add this block's kobject */ | ||
478 | err = kobject_register(&block->kobj); | 550 | err = kobject_register(&block->kobj); |
479 | if (err) { | 551 | if (err) { |
480 | debugf1("%s()Failed to register instance '%s'\n", | 552 | debugf1("%s() Failed to register instance '%s'\n", |
481 | __func__, block->name); | 553 | __func__, block->name); |
482 | return err; | 554 | kobject_put(main_kobj); |
555 | err = -ENODEV; | ||
556 | goto err_out; | ||
483 | } | 557 | } |
484 | 558 | ||
485 | /* If there are driver level block attributes, then added them | 559 | /* If there are driver level block attributes, then added them |
486 | * to the block kobject | 560 | * to the block kobject |
487 | */ | 561 | */ |
488 | sysfs_attrib = block->block_attributes; | 562 | sysfs_attrib = block->block_attributes; |
489 | if (sysfs_attrib != NULL) { | 563 | if (sysfs_attrib) { |
490 | for (i = 0; i < block->nr_attribs; i++) { | 564 | for (i = 0; i < block->nr_attribs; i++) { |
491 | err = sysfs_create_file(&block->kobj, | 565 | err = sysfs_create_file(&block->kobj, |
492 | (struct attribute *) &sysfs_attrib[i]); | 566 | (struct attribute *) sysfs_attrib); |
493 | if (err) | 567 | if (err) |
494 | goto err_on_attrib; | 568 | goto err_on_attrib; |
495 | 569 | ||
@@ -499,30 +573,41 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, | |||
499 | 573 | ||
500 | return 0; | 574 | return 0; |
501 | 575 | ||
576 | /* Error unwind stack */ | ||
502 | err_on_attrib: | 577 | err_on_attrib: |
503 | kobject_unregister(&block->kobj); | 578 | kobject_unregister(&block->kobj); |
504 | 579 | ||
580 | err_out: | ||
505 | return err; | 581 | return err; |
506 | } | 582 | } |
507 | 583 | ||
508 | /* | 584 | /* |
509 | * edac_device_delete_block(edac_dev,j); | 585 | * edac_device_delete_block(edac_dev,block); |
510 | */ | 586 | */ |
511 | static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, | 587 | static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, |
512 | struct edac_device_instance *instance, | 588 | struct edac_device_block *block) |
513 | int idx) | ||
514 | { | 589 | { |
515 | struct edac_device_block *block; | 590 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; |
591 | int i; | ||
516 | 592 | ||
517 | block = &instance->blocks[idx]; | 593 | /* if this block has 'attributes' then we need to iterate over the list |
594 | * and 'remove' the attributes on this block | ||
595 | */ | ||
596 | sysfs_attrib = block->block_attributes; | ||
597 | if (sysfs_attrib && block->nr_attribs) { | ||
598 | for (i = 0; i < block->nr_attribs; i++) { | ||
599 | sysfs_remove_file(&block->kobj, | ||
600 | (struct attribute *) sysfs_attrib); | ||
601 | } | ||
602 | } | ||
518 | 603 | ||
519 | /* unregister this block's kobject */ | 604 | /* unregister this block's kobject, SEE: |
520 | init_completion(&block->kobj_complete); | 605 | * edac_device_ctrl_block_release() callback operation |
606 | */ | ||
521 | kobject_unregister(&block->kobj); | 607 | kobject_unregister(&block->kobj); |
522 | wait_for_completion(&block->kobj_complete); | ||
523 | } | 608 | } |
524 | 609 | ||
525 | /************** instance ctor/dtor code ************/ | 610 | /* instance ctor/dtor code */ |
526 | 611 | ||
527 | /* | 612 | /* |
528 | * edac_device_create_instance | 613 | * edac_device_create_instance |
@@ -534,6 +619,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
534 | int i, j; | 619 | int i, j; |
535 | int err; | 620 | int err; |
536 | struct edac_device_instance *instance; | 621 | struct edac_device_instance *instance; |
622 | struct kobject *main_kobj; | ||
537 | 623 | ||
538 | instance = &edac_dev->instances[idx]; | 624 | instance = &edac_dev->instances[idx]; |
539 | 625 | ||
@@ -543,16 +629,28 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
543 | /* set this new device under the edac_device main kobject */ | 629 | /* set this new device under the edac_device main kobject */ |
544 | instance->kobj.parent = &edac_dev->kobj; | 630 | instance->kobj.parent = &edac_dev->kobj; |
545 | instance->kobj.ktype = &ktype_instance_ctrl; | 631 | instance->kobj.ktype = &ktype_instance_ctrl; |
632 | instance->ctl = edac_dev; | ||
546 | 633 | ||
547 | err = kobject_set_name(&instance->kobj, "%s", instance->name); | 634 | err = kobject_set_name(&instance->kobj, "%s", instance->name); |
548 | if (err) | 635 | if (err) |
549 | return err; | 636 | goto err_out; |
637 | |||
638 | /* bump the main kobject's reference count for this controller | ||
639 | * and this instance is dependant on the main | ||
640 | */ | ||
641 | main_kobj = kobject_get(&edac_dev->kobj); | ||
642 | if (!main_kobj) { | ||
643 | err = -ENODEV; | ||
644 | goto err_out; | ||
645 | } | ||
550 | 646 | ||
647 | /* Formally register this instance's kobject */ | ||
551 | err = kobject_register(&instance->kobj); | 648 | err = kobject_register(&instance->kobj); |
552 | if (err != 0) { | 649 | if (err != 0) { |
553 | debugf2("%s() Failed to register instance '%s'\n", | 650 | debugf2("%s() Failed to register instance '%s'\n", |
554 | __func__, instance->name); | 651 | __func__, instance->name); |
555 | return err; | 652 | kobject_put(main_kobj); |
653 | goto err_out; | ||
556 | } | 654 | } |
557 | 655 | ||
558 | debugf1("%s() now register '%d' blocks for instance %d\n", | 656 | debugf1("%s() now register '%d' blocks for instance %d\n", |
@@ -560,11 +658,14 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
560 | 658 | ||
561 | /* register all blocks of this instance */ | 659 | /* register all blocks of this instance */ |
562 | for (i = 0; i < instance->nr_blocks; i++) { | 660 | for (i = 0; i < instance->nr_blocks; i++) { |
563 | err = edac_device_create_block(edac_dev, instance, i); | 661 | err = edac_device_create_block(edac_dev, instance, |
662 | &instance->blocks[i]); | ||
564 | if (err) { | 663 | if (err) { |
664 | /* If any fail, remove all previous ones */ | ||
565 | for (j = 0; j < i; j++) | 665 | for (j = 0; j < i; j++) |
566 | edac_device_delete_block(edac_dev, instance, j); | 666 | edac_device_delete_block(edac_dev, |
567 | return err; | 667 | &instance->blocks[j]); |
668 | goto err_release_instance_kobj; | ||
568 | } | 669 | } |
569 | } | 670 | } |
570 | 671 | ||
@@ -572,6 +673,13 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
572 | __func__, idx, instance->name); | 673 | __func__, idx, instance->name); |
573 | 674 | ||
574 | return 0; | 675 | return 0; |
676 | |||
677 | /* error unwind stack */ | ||
678 | err_release_instance_kobj: | ||
679 | kobject_unregister(&instance->kobj); | ||
680 | |||
681 | err_out: | ||
682 | return err; | ||
575 | } | 683 | } |
576 | 684 | ||
577 | /* | 685 | /* |
@@ -581,19 +689,19 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
581 | static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, | 689 | static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, |
582 | int idx) | 690 | int idx) |
583 | { | 691 | { |
584 | int i; | ||
585 | struct edac_device_instance *instance; | 692 | struct edac_device_instance *instance; |
693 | int i; | ||
586 | 694 | ||
587 | instance = &edac_dev->instances[idx]; | 695 | instance = &edac_dev->instances[idx]; |
588 | 696 | ||
589 | /* unregister all blocks in this instance */ | 697 | /* unregister all blocks in this instance */ |
590 | for (i = 0; i < instance->nr_blocks; i++) | 698 | for (i = 0; i < instance->nr_blocks; i++) |
591 | edac_device_delete_block(edac_dev, instance, i); | 699 | edac_device_delete_block(edac_dev, &instance->blocks[i]); |
592 | 700 | ||
593 | /* unregister this instance's kobject */ | 701 | /* unregister this instance's kobject, SEE: |
594 | init_completion(&instance->kobj_complete); | 702 | * edac_device_ctrl_instance_release() for callback operation |
703 | */ | ||
595 | kobject_unregister(&instance->kobj); | 704 | kobject_unregister(&instance->kobj); |
596 | wait_for_completion(&instance->kobj_complete); | ||
597 | } | 705 | } |
598 | 706 | ||
599 | /* | 707 | /* |
@@ -635,39 +743,69 @@ static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev) | |||
635 | edac_device_delete_instance(edac_dev, i); | 743 | edac_device_delete_instance(edac_dev, i); |
636 | } | 744 | } |
637 | 745 | ||
638 | /******************* edac_dev sysfs ctor/dtor code *************/ | 746 | /* edac_dev sysfs ctor/dtor code */ |
639 | 747 | ||
640 | /* | 748 | /* |
641 | * edac_device_add_sysfs_attributes | 749 | * edac_device_add_main_sysfs_attributes |
642 | * add some attributes to this instance's main kobject | 750 | * add some attributes to this instance's main kobject |
643 | */ | 751 | */ |
644 | static int edac_device_add_sysfs_attributes( | 752 | static int edac_device_add_main_sysfs_attributes( |
645 | struct edac_device_ctl_info *edac_dev) | 753 | struct edac_device_ctl_info *edac_dev) |
646 | { | 754 | { |
647 | int err; | ||
648 | struct edac_dev_sysfs_attribute *sysfs_attrib; | 755 | struct edac_dev_sysfs_attribute *sysfs_attrib; |
756 | int err = 0; | ||
649 | 757 | ||
650 | /* point to the start of the array and iterate over it | ||
651 | * adding each attribute listed to this mci instance's kobject | ||
652 | */ | ||
653 | sysfs_attrib = edac_dev->sysfs_attributes; | 758 | sysfs_attrib = edac_dev->sysfs_attributes; |
654 | 759 | if (sysfs_attrib) { | |
655 | while (sysfs_attrib->attr.name != NULL) { | 760 | /* iterate over the array and create an attribute for each |
656 | err = sysfs_create_file(&edac_dev->kobj, | 761 | * entry in the list |
762 | */ | ||
763 | while (sysfs_attrib->attr.name != NULL) { | ||
764 | err = sysfs_create_file(&edac_dev->kobj, | ||
657 | (struct attribute*) sysfs_attrib); | 765 | (struct attribute*) sysfs_attrib); |
658 | if (err) | 766 | if (err) |
659 | return err; | 767 | goto err_out; |
660 | 768 | ||
661 | sysfs_attrib++; | 769 | sysfs_attrib++; |
770 | } | ||
662 | } | 771 | } |
663 | 772 | ||
664 | return 0; | 773 | err_out: |
774 | return err; | ||
775 | } | ||
776 | |||
777 | /* | ||
778 | * edac_device_remove_main_sysfs_attributes | ||
779 | * remove any attributes to this instance's main kobject | ||
780 | */ | ||
781 | static void edac_device_remove_main_sysfs_attributes( | ||
782 | struct edac_device_ctl_info *edac_dev) | ||
783 | { | ||
784 | struct edac_dev_sysfs_attribute *sysfs_attrib; | ||
785 | |||
786 | /* if there are main attributes, defined, remove them. First, | ||
787 | * point to the start of the array and iterate over it | ||
788 | * removing each attribute listed from this device's instance's kobject | ||
789 | */ | ||
790 | sysfs_attrib = edac_dev->sysfs_attributes; | ||
791 | if (sysfs_attrib) { | ||
792 | while (sysfs_attrib->attr.name != NULL) { | ||
793 | sysfs_remove_file(&edac_dev->kobj, | ||
794 | (struct attribute *) sysfs_attrib); | ||
795 | sysfs_attrib++; | ||
796 | } | ||
797 | } | ||
665 | } | 798 | } |
666 | 799 | ||
667 | /* | 800 | /* |
668 | * edac_device_create_sysfs() Constructor | 801 | * edac_device_create_sysfs() Constructor |
669 | * | 802 | * |
670 | * Create a new edac_device kobject instance, | 803 | * accept a created edac_device control structure |
804 | * and 'export' it to sysfs. The 'main' kobj should already have been | ||
805 | * created. 'instance' and 'block' kobjects should be registered | ||
806 | * along with any 'block' attributes from the low driver. In addition, | ||
807 | * the main attributes (if any) are connected to the main kobject of | ||
808 | * the control structure. | ||
671 | * | 809 | * |
672 | * Return: | 810 | * Return: |
673 | * 0 Success | 811 | * 0 Success |
@@ -678,23 +816,13 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
678 | int err; | 816 | int err; |
679 | struct kobject *edac_kobj = &edac_dev->kobj; | 817 | struct kobject *edac_kobj = &edac_dev->kobj; |
680 | 818 | ||
681 | /* register this instance's main kobj with the edac class kobj */ | ||
682 | err = edac_device_register_main_kobj(edac_dev); | ||
683 | if (err) | ||
684 | return err; | ||
685 | |||
686 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); | 819 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); |
687 | 820 | ||
688 | /* If the low level driver requests some sysfs entries | 821 | /* go create any main attributes callers wants */ |
689 | * then go create them here | 822 | err = edac_device_add_main_sysfs_attributes(edac_dev); |
690 | */ | 823 | if (err) { |
691 | if (edac_dev->sysfs_attributes != NULL) { | 824 | debugf0("%s() failed to add sysfs attribs\n", __func__); |
692 | err = edac_device_add_sysfs_attributes(edac_dev); | 825 | goto err_out; |
693 | if (err) { | ||
694 | debugf0("%s() failed to add sysfs attribs\n", | ||
695 | __func__); | ||
696 | goto err_unreg_object; | ||
697 | } | ||
698 | } | 826 | } |
699 | 827 | ||
700 | /* create a symlink from the edac device | 828 | /* create a symlink from the edac device |
@@ -705,16 +833,23 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
705 | if (err) { | 833 | if (err) { |
706 | debugf0("%s() sysfs_create_link() returned err= %d\n", | 834 | debugf0("%s() sysfs_create_link() returned err= %d\n", |
707 | __func__, err); | 835 | __func__, err); |
708 | goto err_unreg_object; | 836 | goto err_remove_main_attribs; |
709 | } | 837 | } |
710 | 838 | ||
711 | debugf0("%s() calling create-instances, idx=%d\n", | 839 | /* Create the first level instance directories |
712 | __func__, edac_dev->dev_idx); | 840 | * In turn, the nested blocks beneath the instances will |
713 | 841 | * be registered as well | |
714 | /* Create the first level instance directories */ | 842 | */ |
715 | err = edac_device_create_instances(edac_dev); | 843 | err = edac_device_create_instances(edac_dev); |
716 | if (err) | 844 | if (err) { |
845 | debugf0("%s() edac_device_create_instances() " | ||
846 | "returned err= %d\n", __func__, err); | ||
717 | goto err_remove_link; | 847 | goto err_remove_link; |
848 | } | ||
849 | |||
850 | |||
851 | debugf0("%s() calling create-instances, idx=%d\n", | ||
852 | __func__, edac_dev->dev_idx); | ||
718 | 853 | ||
719 | return 0; | 854 | return 0; |
720 | 855 | ||
@@ -723,26 +858,28 @@ err_remove_link: | |||
723 | /* remove the sym link */ | 858 | /* remove the sym link */ |
724 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | 859 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); |
725 | 860 | ||
726 | err_unreg_object: | 861 | err_remove_main_attribs: |
727 | edac_device_unregister_main_kobj(edac_dev); | 862 | edac_device_remove_main_sysfs_attributes(edac_dev); |
728 | 863 | ||
864 | err_out: | ||
729 | return err; | 865 | return err; |
730 | } | 866 | } |
731 | 867 | ||
732 | /* | 868 | /* |
733 | * edac_device_remove_sysfs() destructor | 869 | * edac_device_remove_sysfs() destructor |
734 | * | 870 | * |
735 | * remove a edac_device instance | 871 | * given an edac_device struct, tear down the kobject resources |
736 | */ | 872 | */ |
737 | void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev) | 873 | void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev) |
738 | { | 874 | { |
739 | debugf0("%s()\n", __func__); | 875 | debugf0("%s()\n", __func__); |
740 | 876 | ||
741 | edac_device_delete_instances(edac_dev); | 877 | /* remove any main attributes for this device */ |
878 | edac_device_remove_main_sysfs_attributes(edac_dev); | ||
742 | 879 | ||
743 | /* remove the sym link */ | 880 | /* remove the device sym link */ |
744 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | 881 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); |
745 | 882 | ||
746 | /* unregister the instance's main kobj */ | 883 | /* walk the instance/block kobject tree, deconstructing it */ |
747 | edac_device_unregister_main_kobj(edac_dev); | 884 | edac_device_delete_instances(edac_dev); |
748 | } | 885 | } |
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 6368cc658fc6..a2134dfc3cc6 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
@@ -37,6 +37,10 @@ extern int edac_mc_get_panic_on_ue(void); | |||
37 | extern int edac_get_poll_msec(void); | 37 | extern int edac_get_poll_msec(void); |
38 | extern int edac_mc_get_poll_msec(void); | 38 | extern int edac_mc_get_poll_msec(void); |
39 | 39 | ||
40 | extern int edac_device_register_sysfs_main_kobj( | ||
41 | struct edac_device_ctl_info *edac_dev); | ||
42 | extern void edac_device_unregister_sysfs_main_kobj( | ||
43 | struct edac_device_ctl_info *edac_dev); | ||
40 | extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); | 44 | extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); |
41 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); | 45 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); |
42 | extern struct sysdev_class *edac_get_edac_class(void); | 46 | extern struct sysdev_class *edac_get_edac_class(void); |