.. | .. |
---|
11 | 11 | #include <linux/slab.h> |
---|
12 | 12 | #include <linux/percpu.h> |
---|
13 | 13 | |
---|
| 14 | +#include <asm/sections.h> |
---|
| 15 | + |
---|
14 | 16 | #include "base.h" |
---|
15 | 17 | |
---|
16 | 18 | struct devres_node { |
---|
.. | .. |
---|
87 | 89 | return NULL; |
---|
88 | 90 | } |
---|
89 | 91 | |
---|
| 92 | +static bool check_dr_size(size_t size, size_t *tot_size) |
---|
| 93 | +{ |
---|
| 94 | + /* We must catch any near-SIZE_MAX cases that could overflow. */ |
---|
| 95 | + if (unlikely(check_add_overflow(sizeof(struct devres), |
---|
| 96 | + size, tot_size))) |
---|
| 97 | + return false; |
---|
| 98 | + |
---|
| 99 | + return true; |
---|
| 100 | +} |
---|
| 101 | + |
---|
90 | 102 | static __always_inline struct devres * alloc_dr(dr_release_t release, |
---|
91 | 103 | size_t size, gfp_t gfp, int nid) |
---|
92 | 104 | { |
---|
93 | 105 | size_t tot_size; |
---|
94 | 106 | struct devres *dr; |
---|
95 | 107 | |
---|
96 | | - /* We must catch any near-SIZE_MAX cases that could overflow. */ |
---|
97 | | - if (unlikely(check_add_overflow(sizeof(struct devres), size, |
---|
98 | | - &tot_size))) |
---|
| 108 | + if (!check_dr_size(size, &tot_size)) |
---|
99 | 109 | return NULL; |
---|
100 | 110 | |
---|
101 | 111 | dr = kmalloc_node_track_caller(tot_size, gfp, nid); |
---|
.. | .. |
---|
114 | 124 | devres_log(dev, node, "ADD"); |
---|
115 | 125 | BUG_ON(!list_empty(&node->entry)); |
---|
116 | 126 | list_add_tail(&node->entry, &dev->devres_head); |
---|
| 127 | +} |
---|
| 128 | + |
---|
| 129 | +static void replace_dr(struct device *dev, |
---|
| 130 | + struct devres_node *old, struct devres_node *new) |
---|
| 131 | +{ |
---|
| 132 | + devres_log(dev, old, "REPLACE"); |
---|
| 133 | + BUG_ON(!list_empty(&new->entry)); |
---|
| 134 | + list_replace(&old->entry, &new->entry); |
---|
117 | 135 | } |
---|
118 | 136 | |
---|
119 | 137 | #ifdef CONFIG_DEBUG_DEVRES |
---|
.. | .. |
---|
753 | 771 | |
---|
754 | 772 | WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match, |
---|
755 | 773 | &devres)); |
---|
756 | | - |
---|
757 | 774 | } |
---|
758 | 775 | EXPORT_SYMBOL_GPL(devm_remove_action); |
---|
| 776 | + |
---|
| 777 | +/** |
---|
| 778 | + * devm_release_action() - release previously added custom action |
---|
| 779 | + * @dev: Device that owns the action |
---|
| 780 | + * @action: Function implementing the action |
---|
| 781 | + * @data: Pointer to data passed to @action implementation |
---|
| 782 | + * |
---|
| 783 | + * Releases and removes instance of @action previously added by |
---|
| 784 | + * devm_add_action(). Both action and data should match one of the |
---|
| 785 | + * existing entries. |
---|
| 786 | + */ |
---|
| 787 | +void devm_release_action(struct device *dev, void (*action)(void *), void *data) |
---|
| 788 | +{ |
---|
| 789 | + struct action_devres devres = { |
---|
| 790 | + .data = data, |
---|
| 791 | + .action = action, |
---|
| 792 | + }; |
---|
| 793 | + |
---|
| 794 | + WARN_ON(devres_release(dev, devm_action_release, devm_action_match, |
---|
| 795 | + &devres)); |
---|
| 796 | + |
---|
| 797 | +} |
---|
| 798 | +EXPORT_SYMBOL_GPL(devm_release_action); |
---|
759 | 799 | |
---|
760 | 800 | /* |
---|
761 | 801 | * Managed kmalloc/kfree |
---|
.. | .. |
---|
783 | 823 | * RETURNS: |
---|
784 | 824 | * Pointer to allocated memory on success, NULL on failure. |
---|
785 | 825 | */ |
---|
786 | | -void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) |
---|
| 826 | +void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) |
---|
787 | 827 | { |
---|
788 | 828 | struct devres *dr; |
---|
| 829 | + |
---|
| 830 | + if (unlikely(!size)) |
---|
| 831 | + return ZERO_SIZE_PTR; |
---|
789 | 832 | |
---|
790 | 833 | /* use raw alloc_dr for kmalloc caller tracing */ |
---|
791 | 834 | dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev)); |
---|
.. | .. |
---|
801 | 844 | return dr->data; |
---|
802 | 845 | } |
---|
803 | 846 | EXPORT_SYMBOL_GPL(devm_kmalloc); |
---|
| 847 | + |
---|
| 848 | +/** |
---|
| 849 | + * devm_krealloc - Resource-managed krealloc() |
---|
| 850 | + * @dev: Device to re-allocate memory for |
---|
| 851 | + * @ptr: Pointer to the memory chunk to re-allocate |
---|
| 852 | + * @new_size: New allocation size |
---|
| 853 | + * @gfp: Allocation gfp flags |
---|
| 854 | + * |
---|
| 855 | + * Managed krealloc(). Resizes the memory chunk allocated with devm_kmalloc(). |
---|
| 856 | + * Behaves similarly to regular krealloc(): if @ptr is NULL or ZERO_SIZE_PTR, |
---|
| 857 | + * it's the equivalent of devm_kmalloc(). If new_size is zero, it frees the |
---|
| 858 | + * previously allocated memory and returns ZERO_SIZE_PTR. This function doesn't |
---|
| 859 | + * change the order in which the release callback for the re-alloc'ed devres |
---|
| 860 | + * will be called (except when falling back to devm_kmalloc() or when freeing |
---|
| 861 | + * resources when new_size is zero). The contents of the memory are preserved |
---|
| 862 | + * up to the lesser of new and old sizes. |
---|
| 863 | + */ |
---|
| 864 | +void *devm_krealloc(struct device *dev, void *ptr, size_t new_size, gfp_t gfp) |
---|
| 865 | +{ |
---|
| 866 | + size_t total_new_size, total_old_size; |
---|
| 867 | + struct devres *old_dr, *new_dr; |
---|
| 868 | + unsigned long flags; |
---|
| 869 | + |
---|
| 870 | + if (unlikely(!new_size)) { |
---|
| 871 | + devm_kfree(dev, ptr); |
---|
| 872 | + return ZERO_SIZE_PTR; |
---|
| 873 | + } |
---|
| 874 | + |
---|
| 875 | + if (unlikely(ZERO_OR_NULL_PTR(ptr))) |
---|
| 876 | + return devm_kmalloc(dev, new_size, gfp); |
---|
| 877 | + |
---|
| 878 | + if (WARN_ON(is_kernel_rodata((unsigned long)ptr))) |
---|
| 879 | + /* |
---|
| 880 | + * We cannot reliably realloc a const string returned by |
---|
| 881 | + * devm_kstrdup_const(). |
---|
| 882 | + */ |
---|
| 883 | + return NULL; |
---|
| 884 | + |
---|
| 885 | + if (!check_dr_size(new_size, &total_new_size)) |
---|
| 886 | + return NULL; |
---|
| 887 | + |
---|
| 888 | + total_old_size = ksize(container_of(ptr, struct devres, data)); |
---|
| 889 | + if (total_old_size == 0) { |
---|
| 890 | + WARN(1, "Pointer doesn't point to dynamically allocated memory."); |
---|
| 891 | + return NULL; |
---|
| 892 | + } |
---|
| 893 | + |
---|
| 894 | + /* |
---|
| 895 | + * If new size is smaller or equal to the actual number of bytes |
---|
| 896 | + * allocated previously - just return the same pointer. |
---|
| 897 | + */ |
---|
| 898 | + if (total_new_size <= total_old_size) |
---|
| 899 | + return ptr; |
---|
| 900 | + |
---|
| 901 | + /* |
---|
| 902 | + * Otherwise: allocate new, larger chunk. We need to allocate before |
---|
| 903 | + * taking the lock as most probably the caller uses GFP_KERNEL. |
---|
| 904 | + */ |
---|
| 905 | + new_dr = alloc_dr(devm_kmalloc_release, |
---|
| 906 | + total_new_size, gfp, dev_to_node(dev)); |
---|
| 907 | + if (!new_dr) |
---|
| 908 | + return NULL; |
---|
| 909 | + |
---|
| 910 | + /* |
---|
| 911 | + * The spinlock protects the linked list against concurrent |
---|
| 912 | + * modifications but not the resource itself. |
---|
| 913 | + */ |
---|
| 914 | + spin_lock_irqsave(&dev->devres_lock, flags); |
---|
| 915 | + |
---|
| 916 | + old_dr = find_dr(dev, devm_kmalloc_release, devm_kmalloc_match, ptr); |
---|
| 917 | + if (!old_dr) { |
---|
| 918 | + spin_unlock_irqrestore(&dev->devres_lock, flags); |
---|
| 919 | + kfree(new_dr); |
---|
| 920 | + WARN(1, "Memory chunk not managed or managed by a different device."); |
---|
| 921 | + return NULL; |
---|
| 922 | + } |
---|
| 923 | + |
---|
| 924 | + replace_dr(dev, &old_dr->node, &new_dr->node); |
---|
| 925 | + |
---|
| 926 | + spin_unlock_irqrestore(&dev->devres_lock, flags); |
---|
| 927 | + |
---|
| 928 | + /* |
---|
| 929 | + * We can copy the memory contents after releasing the lock as we're |
---|
| 930 | + * no longer modyfing the list links. |
---|
| 931 | + */ |
---|
| 932 | + memcpy(new_dr->data, old_dr->data, |
---|
| 933 | + total_old_size - offsetof(struct devres, data)); |
---|
| 934 | + /* |
---|
| 935 | + * Same for releasing the old devres - it's now been removed from the |
---|
| 936 | + * list. This is also the reason why we must not use devm_kfree() - the |
---|
| 937 | + * links are no longer valid. |
---|
| 938 | + */ |
---|
| 939 | + kfree(old_dr); |
---|
| 940 | + |
---|
| 941 | + return new_dr->data; |
---|
| 942 | +} |
---|
| 943 | +EXPORT_SYMBOL_GPL(devm_krealloc); |
---|
804 | 944 | |
---|
805 | 945 | /** |
---|
806 | 946 | * devm_kstrdup - Allocate resource managed space and |
---|
.. | .. |
---|
827 | 967 | return buf; |
---|
828 | 968 | } |
---|
829 | 969 | EXPORT_SYMBOL_GPL(devm_kstrdup); |
---|
| 970 | + |
---|
| 971 | +/** |
---|
| 972 | + * devm_kstrdup_const - resource managed conditional string duplication |
---|
| 973 | + * @dev: device for which to duplicate the string |
---|
| 974 | + * @s: the string to duplicate |
---|
| 975 | + * @gfp: the GFP mask used in the kmalloc() call when allocating memory |
---|
| 976 | + * |
---|
| 977 | + * Strings allocated by devm_kstrdup_const will be automatically freed when |
---|
| 978 | + * the associated device is detached. |
---|
| 979 | + * |
---|
| 980 | + * RETURNS: |
---|
| 981 | + * Source string if it is in .rodata section otherwise it falls back to |
---|
| 982 | + * devm_kstrdup. |
---|
| 983 | + */ |
---|
| 984 | +const char *devm_kstrdup_const(struct device *dev, const char *s, gfp_t gfp) |
---|
| 985 | +{ |
---|
| 986 | + if (is_kernel_rodata((unsigned long)s)) |
---|
| 987 | + return s; |
---|
| 988 | + |
---|
| 989 | + return devm_kstrdup(dev, s, gfp); |
---|
| 990 | +} |
---|
| 991 | +EXPORT_SYMBOL_GPL(devm_kstrdup_const); |
---|
830 | 992 | |
---|
831 | 993 | /** |
---|
832 | 994 | * devm_kvasprintf - Allocate resource managed space and format a string |
---|
.. | .. |
---|
891 | 1053 | * |
---|
892 | 1054 | * Free memory allocated with devm_kmalloc(). |
---|
893 | 1055 | */ |
---|
894 | | -void devm_kfree(struct device *dev, void *p) |
---|
| 1056 | +void devm_kfree(struct device *dev, const void *p) |
---|
895 | 1057 | { |
---|
896 | 1058 | int rc; |
---|
897 | 1059 | |
---|
898 | | - rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); |
---|
| 1060 | + /* |
---|
| 1061 | + * Special cases: pointer to a string in .rodata returned by |
---|
| 1062 | + * devm_kstrdup_const() or NULL/ZERO ptr. |
---|
| 1063 | + */ |
---|
| 1064 | + if (unlikely(is_kernel_rodata((unsigned long)p) || ZERO_OR_NULL_PTR(p))) |
---|
| 1065 | + return; |
---|
| 1066 | + |
---|
| 1067 | + rc = devres_destroy(dev, devm_kmalloc_release, |
---|
| 1068 | + devm_kmalloc_match, (void *)p); |
---|
899 | 1069 | WARN_ON(rc); |
---|
900 | 1070 | } |
---|
901 | 1071 | EXPORT_SYMBOL_GPL(devm_kfree); |
---|