Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Takashi Iwai and committed by
Borislav Petkov
2c1946b6 72601945

+71 -88
+71 -88
drivers/edac/edac_mc_sysfs.c
··· 323 323 channel_dimm_label_show, channel_dimm_label_store, 5); 324 324 325 325 /* Total possible dynamic DIMM Label attribute file table */ 326 - static struct device_attribute *dynamic_csrow_dimm_attr[] = { 327 - &dev_attr_legacy_ch0_dimm_label.attr, 328 - &dev_attr_legacy_ch1_dimm_label.attr, 329 - &dev_attr_legacy_ch2_dimm_label.attr, 330 - &dev_attr_legacy_ch3_dimm_label.attr, 331 - &dev_attr_legacy_ch4_dimm_label.attr, 332 - &dev_attr_legacy_ch5_dimm_label.attr 326 + static struct attribute *dynamic_csrow_dimm_attr[] = { 327 + &dev_attr_legacy_ch0_dimm_label.attr.attr, 328 + &dev_attr_legacy_ch1_dimm_label.attr.attr, 329 + &dev_attr_legacy_ch2_dimm_label.attr.attr, 330 + &dev_attr_legacy_ch3_dimm_label.attr.attr, 331 + &dev_attr_legacy_ch4_dimm_label.attr.attr, 332 + &dev_attr_legacy_ch5_dimm_label.attr.attr, 333 + NULL 333 334 }; 334 335 335 336 /* possible dynamic channel ce_count attribute files */ ··· 348 347 channel_ce_count_show, NULL, 5); 349 348 350 349 /* Total possible dynamic ce_count attribute file table */ 351 - static struct device_attribute *dynamic_csrow_ce_count_attr[] = { 352 - &dev_attr_legacy_ch0_ce_count.attr, 353 - &dev_attr_legacy_ch1_ce_count.attr, 354 - &dev_attr_legacy_ch2_ce_count.attr, 355 - &dev_attr_legacy_ch3_ce_count.attr, 356 - &dev_attr_legacy_ch4_ce_count.attr, 357 - &dev_attr_legacy_ch5_ce_count.attr 350 + static struct attribute *dynamic_csrow_ce_count_attr[] = { 351 + &dev_attr_legacy_ch0_ce_count.attr.attr, 352 + &dev_attr_legacy_ch1_ce_count.attr.attr, 353 + &dev_attr_legacy_ch2_ce_count.attr.attr, 354 + &dev_attr_legacy_ch3_ce_count.attr.attr, 355 + &dev_attr_legacy_ch4_ce_count.attr.attr, 356 + &dev_attr_legacy_ch5_ce_count.attr.attr, 357 + NULL 358 + }; 359 + 360 + static umode_t csrow_dev_is_visible(struct kobject *kobj, 361 + struct attribute *attr, int idx) 362 + { 363 + struct device *dev = kobj_to_dev(kobj); 364 + struct csrow_info *csrow = container_of(dev, struct csrow_info, dev); 365 + 366 + if (idx >= csrow->nr_channels) 367 + return 0; 368 + /* Only expose populated DIMMs */ 369 + if (!csrow->channels[idx]->dimm->nr_pages) 370 + return 0; 371 + return attr->mode; 372 + } 373 + 374 + 375 + static const struct attribute_group csrow_dev_dimm_group = { 376 + .attrs = dynamic_csrow_dimm_attr, 377 + .is_visible = csrow_dev_is_visible, 378 + }; 379 + 380 + static const struct attribute_group csrow_dev_ce_count_group = { 381 + .attrs = dynamic_csrow_ce_count_attr, 382 + .is_visible = csrow_dev_is_visible, 383 + }; 384 + 385 + static const struct attribute_group *csrow_dev_groups[] = { 386 + &csrow_dev_dimm_group, 387 + &csrow_dev_ce_count_group, 388 + NULL 358 389 }; 359 390 360 391 static inline int nr_pages_per_csrow(struct csrow_info *csrow) ··· 403 370 static int edac_create_csrow_object(struct mem_ctl_info *mci, 404 371 struct csrow_info *csrow, int index) 405 372 { 406 - int err, chan; 407 - 408 373 if (csrow->nr_channels > EDAC_NR_CHANNELS) 409 374 return -ENODEV; 410 375 411 376 csrow->dev.type = &csrow_attr_type; 412 377 csrow->dev.bus = mci->bus; 378 + csrow->dev.groups = csrow_dev_groups; 413 379 device_initialize(&csrow->dev); 414 380 csrow->dev.parent = &mci->dev; 415 381 csrow->mci = mci; ··· 418 386 edac_dbg(0, "creating (virtual) csrow node %s\n", 419 387 dev_name(&csrow->dev)); 420 388 421 - err = device_add(&csrow->dev); 422 - if (err < 0) 423 - return err; 424 - 425 - for (chan = 0; chan < csrow->nr_channels; chan++) { 426 - /* Only expose populated DIMMs */ 427 - if (!csrow->channels[chan]->dimm->nr_pages) 428 - continue; 429 - err = device_create_file(&csrow->dev, 430 - dynamic_csrow_dimm_attr[chan]); 431 - if (err < 0) 432 - goto error; 433 - err = device_create_file(&csrow->dev, 434 - dynamic_csrow_ce_count_attr[chan]); 435 - if (err < 0) { 436 - device_remove_file(&csrow->dev, 437 - dynamic_csrow_dimm_attr[chan]); 438 - goto error; 439 - } 440 - } 441 - 442 - return 0; 443 - 444 - error: 445 - for (--chan; chan >= 0; chan--) { 446 - device_remove_file(&csrow->dev, 447 - dynamic_csrow_dimm_attr[chan]); 448 - device_remove_file(&csrow->dev, 449 - dynamic_csrow_ce_count_attr[chan]); 450 - } 451 - put_device(&csrow->dev); 452 - 453 - return err; 389 + return device_add(&csrow->dev); 454 390 } 455 391 456 392 /* Create a CSROW object under specifed edac_mc_device */ 457 393 static int edac_create_csrow_objects(struct mem_ctl_info *mci) 458 394 { 459 - int err, i, chan; 395 + int err, i; 460 396 struct csrow_info *csrow; 461 397 462 398 for (i = 0; i < mci->nr_csrows; i++) { ··· 446 446 csrow = mci->csrows[i]; 447 447 if (!nr_pages_per_csrow(csrow)) 448 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 449 put_device(&mci->csrows[i]->dev); 458 450 } 459 451 ··· 454 462 455 463 static void edac_delete_csrow_objects(struct mem_ctl_info *mci) 456 464 { 457 - int i, chan; 465 + int i; 458 466 struct csrow_info *csrow; 459 467 460 468 for (i = mci->nr_csrows - 1; i >= 0; i--) { 461 469 csrow = mci->csrows[i]; 462 470 if (!nr_pages_per_csrow(csrow)) 463 471 continue; 464 - for (chan = csrow->nr_channels - 1; chan >= 0; chan--) { 465 - if (!csrow->channels[chan]->dimm->nr_pages) 466 - continue; 467 - edac_dbg(1, "Removing csrow %d channel %d sysfs nodes\n", 468 - i, chan); 469 - device_remove_file(&csrow->dev, 470 - dynamic_csrow_dimm_attr[chan]); 471 - device_remove_file(&csrow->dev, 472 - dynamic_csrow_ce_count_attr[chan]); 473 - } 474 472 device_unregister(&mci->csrows[i]->dev); 475 473 } 476 474 } ··· 845 863 static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); 846 864 847 865 /* memory scrubber attribute file */ 848 - static DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL); 866 + DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show, 867 + mci_sdram_scrub_rate_store); /* umode set later in is_visible */ 849 868 850 869 static struct attribute *mci_attrs[] = { 851 870 &dev_attr_reset_counters.attr, ··· 858 875 &dev_attr_ue_count.attr, 859 876 &dev_attr_ce_count.attr, 860 877 &dev_attr_max_location.attr, 878 + &dev_attr_sdram_scrub_rate.attr, 861 879 NULL 862 880 }; 863 881 882 + static umode_t mci_attr_is_visible(struct kobject *kobj, 883 + struct attribute *attr, int idx) 884 + { 885 + struct device *dev = kobj_to_dev(kobj); 886 + struct mem_ctl_info *mci = to_mci(dev); 887 + umode_t mode = 0; 888 + 889 + if (attr != &dev_attr_sdram_scrub_rate.attr) 890 + return attr->mode; 891 + if (mci->get_sdram_scrub_rate) 892 + mode |= S_IRUGO; 893 + if (mci->set_sdram_scrub_rate) 894 + mode |= S_IWUSR; 895 + return mode; 896 + } 897 + 864 898 static struct attribute_group mci_attr_grp = { 865 899 .attrs = mci_attrs, 900 + .is_visible = mci_attr_is_visible, 866 901 }; 867 902 868 903 static const struct attribute_group *mci_attr_groups[] = { ··· 1009 1008 goto fail_unregister_bus; 1010 1009 } 1011 1010 1012 - if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) { 1013 - if (mci->get_sdram_scrub_rate) { 1014 - dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO; 1015 - dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show; 1016 - } 1017 - 1018 - if (mci->set_sdram_scrub_rate) { 1019 - dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR; 1020 - dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store; 1021 - } 1022 - 1023 - err = device_create_file(&mci->dev, &dev_attr_sdram_scrub_rate); 1024 - if (err) { 1025 - edac_dbg(1, "failure: create sdram_scrub_rate\n"); 1026 - goto fail_unregister_dev; 1027 - } 1028 - } 1029 1011 /* 1030 1012 * Create the dimm/rank devices 1031 1013 */ ··· 1055 1071 1056 1072 device_unregister(&dimm->dev); 1057 1073 } 1058 - fail_unregister_dev: 1059 1074 device_unregister(&mci->dev); 1060 1075 fail_unregister_bus: 1061 1076 bus_unregister(mci->bus);