Commit c64eefd48c44fa8145ad1f96edabf4a053fffc49
Committed by
Matthew Garrett
1 parent
614ef43222
Exists in
master
and in
39 other branches
WMI: embed struct device directly into wmi_block
Instead of creating wmi_blocks and then register corresponding devices on a separate pass do it all in one shot, since lifetime rules for both objects are the same. This also takes care of leaking devices when device_create fails for one of them. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Showing 1 changed file with 65 additions and 111 deletions Side-by-side Diff
drivers/platform/x86/wmi.c
... | ... | @@ -68,7 +68,7 @@ |
68 | 68 | acpi_handle handle; |
69 | 69 | wmi_notify_handler handler; |
70 | 70 | void *handler_data; |
71 | - struct device *dev; | |
71 | + struct device dev; | |
72 | 72 | }; |
73 | 73 | |
74 | 74 | |
... | ... | @@ -110,7 +110,7 @@ |
110 | 110 | .add = acpi_wmi_add, |
111 | 111 | .remove = acpi_wmi_remove, |
112 | 112 | .notify = acpi_wmi_notify, |
113 | - }, | |
113 | + }, | |
114 | 114 | }; |
115 | 115 | |
116 | 116 | /* |
... | ... | @@ -693,7 +693,9 @@ |
693 | 693 | |
694 | 694 | static void wmi_dev_free(struct device *dev) |
695 | 695 | { |
696 | - kfree(dev); | |
696 | + struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev); | |
697 | + | |
698 | + kfree(wmi_block); | |
697 | 699 | } |
698 | 700 | |
699 | 701 | static struct class wmi_class = { |
700 | 702 | |
701 | 703 | |
702 | 704 | |
703 | 705 | |
704 | 706 | |
705 | 707 | |
706 | 708 | |
707 | 709 | |
708 | 710 | |
709 | 711 | |
710 | 712 | |
711 | 713 | |
712 | 714 | |
713 | 715 | |
714 | 716 | |
715 | 717 | |
716 | 718 | |
717 | 719 | |
718 | 720 | |
... | ... | @@ -703,106 +705,62 @@ |
703 | 705 | .dev_attrs = wmi_dev_attrs, |
704 | 706 | }; |
705 | 707 | |
706 | -static int wmi_create_devs(void) | |
708 | +static struct wmi_block *wmi_create_device(const struct guid_block *gblock, | |
709 | + acpi_handle handle) | |
707 | 710 | { |
708 | - int result; | |
709 | - char guid_string[37]; | |
710 | - struct guid_block *gblock; | |
711 | 711 | struct wmi_block *wblock; |
712 | - struct list_head *p; | |
713 | - struct device *guid_dev; | |
712 | + int error; | |
713 | + char guid_string[37]; | |
714 | 714 | |
715 | - /* Create devices for all the GUIDs */ | |
716 | - list_for_each(p, &wmi_block_list) { | |
717 | - wblock = list_entry(p, struct wmi_block, list); | |
715 | + wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); | |
716 | + if (!wblock) { | |
717 | + error = -ENOMEM; | |
718 | + goto err_out; | |
719 | + } | |
718 | 720 | |
719 | - guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | |
720 | - if (!guid_dev) | |
721 | - return -ENOMEM; | |
721 | + wblock->handle = handle; | |
722 | + wblock->gblock = *gblock; | |
722 | 723 | |
723 | - wblock->dev = guid_dev; | |
724 | + wblock->dev.class = &wmi_class; | |
724 | 725 | |
725 | - guid_dev->class = &wmi_class; | |
726 | - dev_set_drvdata(guid_dev, wblock); | |
726 | + wmi_gtoa(gblock->guid, guid_string); | |
727 | + dev_set_name(&wblock->dev, guid_string); | |
727 | 728 | |
728 | - gblock = &wblock->gblock; | |
729 | + dev_set_drvdata(&wblock->dev, wblock); | |
729 | 730 | |
730 | - wmi_gtoa(gblock->guid, guid_string); | |
731 | - dev_set_name(guid_dev, guid_string); | |
731 | + error = device_register(&wblock->dev); | |
732 | + if (error) | |
733 | + goto err_free; | |
732 | 734 | |
733 | - result = device_register(guid_dev); | |
734 | - if (result) | |
735 | - return result; | |
736 | - } | |
735 | + list_add_tail(&wblock->list, &wmi_block_list); | |
736 | + return wblock; | |
737 | 737 | |
738 | - return 0; | |
738 | +err_free: | |
739 | + kfree(wblock); | |
740 | +err_out: | |
741 | + return ERR_PTR(error); | |
739 | 742 | } |
740 | 743 | |
741 | -static void wmi_remove_devs(void) | |
744 | +static void wmi_free_devices(void) | |
742 | 745 | { |
743 | - struct guid_block *gblock; | |
744 | - struct wmi_block *wblock; | |
745 | - struct list_head *p; | |
746 | - struct device *guid_dev; | |
746 | + struct wmi_block *wblock, *next; | |
747 | 747 | |
748 | 748 | /* Delete devices for all the GUIDs */ |
749 | - list_for_each(p, &wmi_block_list) { | |
750 | - wblock = list_entry(p, struct wmi_block, list); | |
751 | - | |
752 | - guid_dev = wblock->dev; | |
753 | - gblock = &wblock->gblock; | |
754 | - | |
755 | - device_unregister(guid_dev); | |
756 | - } | |
749 | + list_for_each_entry_safe(wblock, next, &wmi_block_list, list) | |
750 | + device_unregister(&wblock->dev); | |
757 | 751 | } |
758 | 752 | |
759 | -static void wmi_class_exit(void) | |
760 | -{ | |
761 | - wmi_remove_devs(); | |
762 | - class_unregister(&wmi_class); | |
763 | -} | |
764 | - | |
765 | -static int wmi_class_init(void) | |
766 | -{ | |
767 | - int ret; | |
768 | - | |
769 | - ret = class_register(&wmi_class); | |
770 | - if (ret) | |
771 | - return ret; | |
772 | - | |
773 | - ret = wmi_create_devs(); | |
774 | - if (ret) | |
775 | - wmi_class_exit(); | |
776 | - | |
777 | - return ret; | |
778 | -} | |
779 | - | |
780 | 753 | static bool guid_already_parsed(const char *guid_string) |
781 | 754 | { |
782 | - struct guid_block *gblock; | |
783 | 755 | struct wmi_block *wblock; |
784 | - struct list_head *p; | |
785 | 756 | |
786 | - list_for_each(p, &wmi_block_list) { | |
787 | - wblock = list_entry(p, struct wmi_block, list); | |
788 | - gblock = &wblock->gblock; | |
789 | - | |
790 | - if (strncmp(gblock->guid, guid_string, 16) == 0) | |
757 | + list_for_each_entry(wblock, &wmi_block_list, list) | |
758 | + if (strncmp(wblock->gblock.guid, guid_string, 16) == 0) | |
791 | 759 | return true; |
792 | - } | |
760 | + | |
793 | 761 | return false; |
794 | 762 | } |
795 | 763 | |
796 | -static void free_wmi_blocks(void) | |
797 | -{ | |
798 | - struct wmi_block *wblock, *next; | |
799 | - | |
800 | - list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { | |
801 | - list_del(&wblock->list); | |
802 | - kfree(wblock); | |
803 | - } | |
804 | -} | |
805 | - | |
806 | 764 | /* |
807 | 765 | * Parse the _WDG method for the GUID data blocks |
808 | 766 | */ |
809 | 767 | |
810 | 768 | |
811 | 769 | |
812 | 770 | |
... | ... | @@ -814,19 +772,19 @@ |
814 | 772 | struct wmi_block *wblock; |
815 | 773 | char guid_string[37]; |
816 | 774 | acpi_status status; |
775 | + int retval; | |
817 | 776 | u32 i, total; |
818 | 777 | |
819 | 778 | status = acpi_evaluate_object(handle, "_WDG", NULL, &out); |
820 | - | |
821 | 779 | if (ACPI_FAILURE(status)) |
822 | - return status; | |
780 | + return -ENXIO; | |
823 | 781 | |
824 | 782 | obj = (union acpi_object *) out.pointer; |
825 | 783 | if (!obj) |
826 | - return AE_ERROR; | |
784 | + return -ENXIO; | |
827 | 785 | |
828 | 786 | if (obj->type != ACPI_TYPE_BUFFER) { |
829 | - status = AE_ERROR; | |
787 | + retval = -ENXIO; | |
830 | 788 | goto out_free_pointer; |
831 | 789 | } |
832 | 790 | |
833 | 791 | |
834 | 792 | |
835 | 793 | |
836 | 794 | |
837 | 795 | |
... | ... | @@ -846,31 +804,29 @@ |
846 | 804 | pr_info("Skipping duplicate GUID %s\n", guid_string); |
847 | 805 | continue; |
848 | 806 | } |
807 | + | |
849 | 808 | if (debug_dump_wdg) |
850 | 809 | wmi_dump_wdg(&gblock[i]); |
851 | 810 | |
852 | - wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); | |
853 | - if (!wblock) { | |
854 | - status = AE_NO_MEMORY; | |
855 | - goto out_free_pointer; | |
811 | + wblock = wmi_create_device(&gblock[i], handle); | |
812 | + if (IS_ERR(wblock)) { | |
813 | + retval = PTR_ERR(wblock); | |
814 | + wmi_free_devices(); | |
815 | + break; | |
856 | 816 | } |
857 | 817 | |
858 | - wblock->gblock = gblock[i]; | |
859 | - wblock->handle = handle; | |
860 | 818 | if (debug_event) { |
861 | 819 | wblock->handler = wmi_notify_debug; |
862 | 820 | wmi_method_enable(wblock, 1); |
863 | 821 | } |
864 | - list_add_tail(&wblock->list, &wmi_block_list); | |
865 | 822 | } |
866 | 823 | |
824 | + retval = 0; | |
825 | + | |
867 | 826 | out_free_pointer: |
868 | 827 | kfree(out.pointer); |
869 | 828 | |
870 | - if (ACPI_FAILURE(status)) | |
871 | - free_wmi_blocks(); | |
872 | - | |
873 | - return status; | |
829 | + return retval; | |
874 | 830 | } |
875 | 831 | |
876 | 832 | /* |
... | ... | @@ -949,6 +905,7 @@ |
949 | 905 | { |
950 | 906 | acpi_remove_address_space_handler(device->handle, |
951 | 907 | ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); |
908 | + wmi_free_devices(); | |
952 | 909 | |
953 | 910 | return 0; |
954 | 911 | } |
... | ... | @@ -956,7 +913,7 @@ |
956 | 913 | static int acpi_wmi_add(struct acpi_device *device) |
957 | 914 | { |
958 | 915 | acpi_status status; |
959 | - int result = 0; | |
916 | + int error; | |
960 | 917 | |
961 | 918 | status = acpi_install_address_space_handler(device->handle, |
962 | 919 | ACPI_ADR_SPACE_EC, |
963 | 920 | |
964 | 921 | |
965 | 922 | |
966 | 923 | |
967 | 924 | |
968 | 925 | |
969 | 926 | |
970 | 927 | |
971 | 928 | |
... | ... | @@ -967,47 +924,44 @@ |
967 | 924 | return -ENODEV; |
968 | 925 | } |
969 | 926 | |
970 | - status = parse_wdg(device->handle); | |
971 | - if (ACPI_FAILURE(status)) { | |
927 | + error = parse_wdg(device->handle); | |
928 | + if (error) { | |
972 | 929 | acpi_remove_address_space_handler(device->handle, |
973 | 930 | ACPI_ADR_SPACE_EC, |
974 | 931 | &acpi_wmi_ec_space_handler); |
975 | 932 | pr_err("Failed to parse WDG method\n"); |
976 | - return -ENODEV; | |
933 | + return error; | |
977 | 934 | } |
978 | 935 | |
979 | - return result; | |
936 | + return 0; | |
980 | 937 | } |
981 | 938 | |
982 | 939 | static int __init acpi_wmi_init(void) |
983 | 940 | { |
984 | - int result; | |
941 | + int error; | |
985 | 942 | |
986 | 943 | if (acpi_disabled) |
987 | 944 | return -ENODEV; |
988 | 945 | |
989 | - result = acpi_bus_register_driver(&acpi_wmi_driver); | |
990 | - if (result < 0) { | |
946 | + error = class_register(&wmi_class); | |
947 | + if (error) | |
948 | + return error; | |
949 | + | |
950 | + error = acpi_bus_register_driver(&acpi_wmi_driver); | |
951 | + if (error) { | |
991 | 952 | pr_err("Error loading mapper\n"); |
992 | - return -ENODEV; | |
953 | + class_unregister(&wmi_class); | |
954 | + return error; | |
993 | 955 | } |
994 | 956 | |
995 | - result = wmi_class_init(); | |
996 | - if (result) { | |
997 | - acpi_bus_unregister_driver(&acpi_wmi_driver); | |
998 | - return result; | |
999 | - } | |
1000 | - | |
1001 | 957 | pr_info("Mapper loaded\n"); |
1002 | - | |
1003 | 958 | return 0; |
1004 | 959 | } |
1005 | 960 | |
1006 | 961 | static void __exit acpi_wmi_exit(void) |
1007 | 962 | { |
1008 | - wmi_class_exit(); | |
1009 | 963 | acpi_bus_unregister_driver(&acpi_wmi_driver); |
1010 | - free_wmi_blocks(); | |
964 | + class_unregister(&wmi_class); | |
1011 | 965 | |
1012 | 966 | pr_info("Mapper unloaded\n"); |
1013 | 967 | } |