| .. | .. |
|---|
| 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); |
|---|