diff options
| author | Takashi Iwai <tiwai@suse.de> | 2015-02-04 05:48:51 -0500 |
|---|---|---|
| committer | Borislav Petkov <bp@suse.de> | 2015-02-23 07:06:58 -0500 |
| commit | 2c1946b6d6290c74c6ad8d0915590d64f33a034d (patch) | |
| tree | 7bee92adb802c5681d740f314f3e52ac95df7f09 /drivers | |
| parent | 7260194595a23e6e762cd444cb40044fd5fa25c0 (diff) | |
EDAC: Use static attribute groups for managing sysfs entries
Instead of manual calls of device_create_file() and
device_remove_file(), use static attribute groups with proper
is_visible callbacks for managing the sysfs entries.
This simplifies the code a lot and avoids the possible races.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: http://lkml.kernel.org/r/1423046938-18111-2-git-send-email-tiwai@suse.de
Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 159 |
1 files changed, 71 insertions, 88 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index c84eecb191ef..0bcd64234a03 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
| @@ -323,13 +323,14 @@ DEVICE_CHANNEL(ch5_dimm_label, S_IRUGO | S_IWUSR, | |||
| 323 | channel_dimm_label_show, channel_dimm_label_store, 5); | 323 | channel_dimm_label_show, channel_dimm_label_store, 5); |
| 324 | 324 | ||
| 325 | /* Total possible dynamic DIMM Label attribute file table */ | 325 | /* Total possible dynamic DIMM Label attribute file table */ |
| 326 | static struct device_attribute *dynamic_csrow_dimm_attr[] = { | 326 | static struct attribute *dynamic_csrow_dimm_attr[] = { |
| 327 | &dev_attr_legacy_ch0_dimm_label.attr, | 327 | &dev_attr_legacy_ch0_dimm_label.attr.attr, |
| 328 | &dev_attr_legacy_ch1_dimm_label.attr, | 328 | &dev_attr_legacy_ch1_dimm_label.attr.attr, |
| 329 | &dev_attr_legacy_ch2_dimm_label.attr, | 329 | &dev_attr_legacy_ch2_dimm_label.attr.attr, |
| 330 | &dev_attr_legacy_ch3_dimm_label.attr, | 330 | &dev_attr_legacy_ch3_dimm_label.attr.attr, |
| 331 | &dev_attr_legacy_ch4_dimm_label.attr, | 331 | &dev_attr_legacy_ch4_dimm_label.attr.attr, |
| 332 | &dev_attr_legacy_ch5_dimm_label.attr | 332 | &dev_attr_legacy_ch5_dimm_label.attr.attr, |
| 333 | NULL | ||
| 333 | }; | 334 | }; |
| 334 | 335 | ||
| 335 | /* possible dynamic channel ce_count attribute files */ | 336 | /* possible dynamic channel ce_count attribute files */ |
| @@ -347,13 +348,45 @@ DEVICE_CHANNEL(ch5_ce_count, S_IRUGO, | |||
| 347 | channel_ce_count_show, NULL, 5); | 348 | channel_ce_count_show, NULL, 5); |
| 348 | 349 | ||
| 349 | /* Total possible dynamic ce_count attribute file table */ | 350 | /* Total possible dynamic ce_count attribute file table */ |
| 350 | static struct device_attribute *dynamic_csrow_ce_count_attr[] = { | 351 | static struct attribute *dynamic_csrow_ce_count_attr[] = { |
| 351 | &dev_attr_legacy_ch0_ce_count.attr, | 352 | &dev_attr_legacy_ch0_ce_count.attr.attr, |
| 352 | &dev_attr_legacy_ch1_ce_count.attr, | 353 | &dev_attr_legacy_ch1_ce_count.attr.attr, |
| 353 | &dev_attr_legacy_ch2_ce_count.attr, | 354 | &dev_attr_legacy_ch2_ce_count.attr.attr, |
| 354 | &dev_attr_legacy_ch3_ce_count.attr, | 355 | &dev_attr_legacy_ch3_ce_count.attr.attr, |
| 355 | &dev_attr_legacy_ch4_ce_count.attr, | 356 | &dev_attr_legacy_ch4_ce_count.attr.attr, |
| 356 | &dev_attr_legacy_ch5_ce_count.attr | 357 | &dev_attr_legacy_ch5_ce_count.attr.attr, |
| 358 | NULL | ||
| 359 | }; | ||
| 360 | |||
| 361 | static umode_t csrow_dev_is_visible(struct kobject *kobj, | ||
| 362 | struct attribute *attr, int idx) | ||
| 363 | { | ||
| 364 | struct device *dev = kobj_to_dev(kobj); | ||
| 365 | struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); | ||
| 366 | |||
| 367 | if (idx >= csrow->nr_channels) | ||
| 368 | return 0; | ||
| 369 | /* Only expose populated DIMMs */ | ||
| 370 | if (!csrow->channels[idx]->dimm->nr_pages) | ||
| 371 | return 0; | ||
| 372 | return attr->mode; | ||
| 373 | } | ||
| 374 | |||
| 375 | |||
| 376 | static const struct attribute_group csrow_dev_dimm_group = { | ||
| 377 | .attrs = dynamic_csrow_dimm_attr, | ||
| 378 | .is_visible = csrow_dev_is_visible, | ||
| 379 | }; | ||
| 380 | |||
| 381 | static const struct attribute_group csrow_dev_ce_count_group = { | ||
| 382 | .attrs = dynamic_csrow_ce_count_attr, | ||
| 383 | .is_visible = csrow_dev_is_visible, | ||
| 384 | }; | ||
| 385 | |||
| 386 | static const struct attribute_group *csrow_dev_groups[] = { | ||
| 387 | &csrow_dev_dimm_group, | ||
| 388 | &csrow_dev_ce_count_group, | ||
| 389 | NULL | ||
| 357 | }; | 390 | }; |
| 358 | 391 | ||
| 359 | static inline int nr_pages_per_csrow(struct csrow_info *csrow) | 392 | static inline int nr_pages_per_csrow(struct csrow_info *csrow) |
| @@ -370,13 +403,12 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow) | |||
| 370 | static int edac_create_csrow_object(struct mem_ctl_info *mci, | 403 | static int edac_create_csrow_object(struct mem_ctl_info *mci, |
| 371 | struct csrow_info *csrow, int index) | 404 | struct csrow_info *csrow, int index) |
| 372 | { | 405 | { |
| 373 | int err, chan; | ||
| 374 | |||
| 375 | if (csrow->nr_channels > EDAC_NR_CHANNELS) | 406 | if (csrow->nr_channels > EDAC_NR_CHANNELS) |
| 376 | return -ENODEV; | 407 | return -ENODEV; |
| 377 | 408 | ||
| 378 | csrow->dev.type = &csrow_attr_type; | 409 | csrow->dev.type = &csrow_attr_type; |
| 379 | csrow->dev.bus = mci->bus; | 410 | csrow->dev.bus = mci->bus; |
| 411 | csrow->dev.groups = csrow_dev_groups; | ||
| 380 | device_initialize(&csrow->dev); | 412 | device_initialize(&csrow->dev); |
| 381 | csrow->dev.parent = &mci->dev; | 413 | csrow->dev.parent = &mci->dev; |
| 382 | csrow->mci = mci; | 414 | csrow->mci = mci; |
| @@ -386,45 +418,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, | |||
| 386 | edac_dbg(0, "creating (virtual) csrow node %s\n", | 418 | edac_dbg(0, "creating (virtual) csrow node %s\n", |
| 387 | dev_name(&csrow->dev)); | 419 | dev_name(&csrow->dev)); |
| 388 | 420 | ||
| 389 | err = device_add(&csrow->dev); | 421 | return device_add(&csrow->dev); |
| 390 | if (err < 0) | ||
| 391 | return err; | ||
| 392 | |||
| 393 | for (chan = 0; chan < csrow->nr_channels; chan++) { | ||
| 394 | /* Only expose populated DIMMs */ | ||
| 395 | if (!csrow->channels[chan]->dimm->nr_pages) | ||
| 396 | continue; | ||
| 397 | err = device_create_file(&csrow->dev, | ||
| 398 | dynamic_csrow_dimm_attr[chan]); | ||
| 399 | if (err < 0) | ||
| 400 | goto error; | ||
| 401 | err = device_create_file(&csrow->dev, | ||
| 402 | dynamic_csrow_ce_count_attr[chan]); | ||
| 403 | if (err < 0) { | ||
| 404 | device_remove_file(&csrow->dev, | ||
| 405 | dynamic_csrow_dimm_attr[chan]); | ||
| 406 | goto error; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | return 0; | ||
| 411 | |||
| 412 | error: | ||
| 413 | for (--chan; chan >= 0; chan--) { | ||
| 414 | device_remove_file(&csrow->dev, | ||
| 415 | dynamic_csrow_dimm_attr[chan]); | ||
| 416 | device_remove_file(&csrow->dev, | ||
| 417 | dynamic_csrow_ce_count_attr[chan]); | ||
| 418 | } | ||
| 419 | put_device(&csrow->dev); | ||
| 420 | |||
| 421 | return err; | ||
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | /* Create a CSROW object under specifed edac_mc_device */ | 424 | /* Create a CSROW object under specifed edac_mc_device */ |
| 425 | static int edac_create_csrow_objects(struct mem_ctl_info *mci) | 425 | static int edac_create_csrow_objects(struct mem_ctl_info *mci) |
| 426 | { | 426 | { |
| 427 | int err, i, chan; | 427 | int err, i; |
| 428 | struct csrow_info *csrow; | 428 | struct csrow_info *csrow; |
| 429 | 429 | ||
| 430 | for (i = 0; i < mci->nr_csrows; i++) { | 430 | for (i = 0; i < mci->nr_csrows; i++) { |
| @@ -446,14 +446,6 @@ error: | |||
| 446 | csrow = mci->csrows[i]; | 446 | csrow = mci->csrows[i]; |
| 447 | if (!nr_pages_per_csrow(csrow)) | 447 | if (!nr_pages_per_csrow(csrow)) |
| 448 | continue; | 448 | continue; |
| 449 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { | ||
| 450 | if (!csrow->channels[chan]->dimm->nr_pages) | ||
| 451 | continue; | ||
| 452 | device_remove_file(&csrow->dev, | ||
| 453 | dynamic_csrow_dimm_attr[chan]); | ||
| 454 | device_remove_file(&csrow->dev, | ||
| 455 | dynamic_csrow_ce_count_attr[chan]); | ||
| 456 | } | ||
| 457 | put_device(&mci->csrows[i]->dev); | 449 | put_device(&mci->csrows[i]->dev); |
| 458 | } | 450 | } |
| 459 | 451 | ||
| @@ -462,23 +454,13 @@ error: | |||
| 462 | 454 | ||
| 463 | static void edac_delete_csrow_objects(struct mem_ctl_info *mci) | 455 | static void edac_delete_csrow_objects(struct mem_ctl_info *mci) |
| 464 | { | 456 | { |
| 465 | int i, chan; | 457 | int i; |
| 466 | struct csrow_info *csrow; | 458 | struct csrow_info *csrow; |
| 467 | 459 | ||
| 468 | for (i = mci->nr_csrows - 1; i >= 0; i--) { | 460 | for (i = mci->nr_csrows - 1; i >= 0; i--) { |
| 469 | csrow = mci->csrows[i]; | 461 | csrow = mci->csrows[i]; |
| 470 | if (!nr_pages_per_csrow(csrow)) | 462 | if (!nr_pages_per_csrow(csrow)) |
| 471 | continue; | 463 | continue; |
| 472 | for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { | ||
| 473 | if (!csrow->channels[chan]->dimm->nr_pages) | ||
| 474 | continue; | ||
| 475 | edac_dbg(1, "Removing csrow %d channel %d sysfs nodes\n", | ||
| 476 | i, chan); | ||
| 477 | device_remove_file(&csrow->dev, | ||
| 478 | dynamic_csrow_dimm_attr[chan]); | ||
| 479 | device_remove_file(&csrow->dev, | ||
| 480 | dynamic_csrow_ce_count_attr[chan]); | ||
| 481 | } | ||
| 482 | device_unregister(&mci->csrows[i]->dev); | 464 | device_unregister(&mci->csrows[i]->dev); |
| 483 | } | 465 | } |
| 484 | } | 466 | } |
| @@ -863,7 +845,8 @@ static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); | |||
| 863 | static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); | 845 | static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); |
| 864 | 846 | ||
| 865 | /* memory scrubber attribute file */ | 847 | /* memory scrubber attribute file */ |
| 866 | static DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL); | 848 | DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show, |
| 849 | mci_sdram_scrub_rate_store); /* umode set later in is_visible */ | ||
| 867 | 850 | ||
| 868 | static struct attribute *mci_attrs[] = { | 851 | static struct attribute *mci_attrs[] = { |
| 869 | &dev_attr_reset_counters.attr, | 852 | &dev_attr_reset_counters.attr, |
| @@ -875,11 +858,29 @@ static struct attribute *mci_attrs[] = { | |||
| 875 | &dev_attr_ue_count.attr, | 858 | &dev_attr_ue_count.attr, |
| 876 | &dev_attr_ce_count.attr, | 859 | &dev_attr_ce_count.attr, |
| 877 | &dev_attr_max_location.attr, | 860 | &dev_attr_max_location.attr, |
| 861 | &dev_attr_sdram_scrub_rate.attr, | ||
| 878 | NULL | 862 | NULL |
| 879 | }; | 863 | }; |
| 880 | 864 | ||
| 865 | static umode_t mci_attr_is_visible(struct kobject *kobj, | ||
| 866 | struct attribute *attr, int idx) | ||
| 867 | { | ||
| 868 | struct device *dev = kobj_to_dev(kobj); | ||
| 869 | struct mem_ctl_info *mci = to_mci(dev); | ||
| 870 | umode_t mode = 0; | ||
| 871 | |||
| 872 | if (attr != &dev_attr_sdram_scrub_rate.attr) | ||
| 873 | return attr->mode; | ||
| 874 | if (mci->get_sdram_scrub_rate) | ||
| 875 | mode |= S_IRUGO; | ||
| 876 | if (mci->set_sdram_scrub_rate) | ||
| 877 | mode |= S_IWUSR; | ||
| 878 | return mode; | ||
| 879 | } | ||
| 880 | |||
| 881 | static struct attribute_group mci_attr_grp = { | 881 | static struct attribute_group mci_attr_grp = { |
| 882 | .attrs = mci_attrs, | 882 | .attrs = mci_attrs, |
| 883 | .is_visible = mci_attr_is_visible, | ||
| 883 | }; | 884 | }; |
| 884 | 885 | ||
| 885 | static const struct attribute_group *mci_attr_groups[] = { | 886 | static const struct attribute_group *mci_attr_groups[] = { |
| @@ -1008,23 +1009,6 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
| 1008 | goto fail_unregister_bus; | 1009 | goto fail_unregister_bus; |
| 1009 | } | 1010 | } |
| 1010 | 1011 | ||
| 1011 | if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) { | ||
| 1012 | if (mci->get_sdram_scrub_rate) { | ||
| 1013 | dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO; | ||
| 1014 | dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | if (mci->set_sdram_scrub_rate) { | ||
| 1018 | dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR; | ||
| 1019 | dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | err = device_create_file(&mci->dev, &dev_attr_sdram_scrub_rate); | ||
| 1023 | if (err) { | ||
| 1024 | edac_dbg(1, "failure: create sdram_scrub_rate\n"); | ||
| 1025 | goto fail_unregister_dev; | ||
| 1026 | } | ||
| 1027 | } | ||
| 1028 | /* | 1012 | /* |
| 1029 | * Create the dimm/rank devices | 1013 | * Create the dimm/rank devices |
| 1030 | */ | 1014 | */ |
| @@ -1071,7 +1055,6 @@ fail_unregister_dimm: | |||
| 1071 | 1055 | ||
| 1072 | device_unregister(&dimm->dev); | 1056 | device_unregister(&dimm->dev); |
| 1073 | } | 1057 | } |
| 1074 | fail_unregister_dev: | ||
| 1075 | device_unregister(&mci->dev); | 1058 | device_unregister(&mci->dev); |
| 1076 | fail_unregister_bus: | 1059 | fail_unregister_bus: |
| 1077 | bus_unregister(mci->bus); | 1060 | bus_unregister(mci->bus); |
