hc
2024-05-10 cde9070d9970eef1f7ec2360586c802a16230ad8
kernel/drivers/base/devres.c
....@@ -11,6 +11,8 @@
1111 #include <linux/slab.h>
1212 #include <linux/percpu.h>
1313
14
+#include <asm/sections.h>
15
+
1416 #include "base.h"
1517
1618 struct devres_node {
....@@ -87,15 +89,23 @@
8789 return NULL;
8890 }
8991
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
+
90102 static __always_inline struct devres * alloc_dr(dr_release_t release,
91103 size_t size, gfp_t gfp, int nid)
92104 {
93105 size_t tot_size;
94106 struct devres *dr;
95107
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))
99109 return NULL;
100110
101111 dr = kmalloc_node_track_caller(tot_size, gfp, nid);
....@@ -114,6 +124,14 @@
114124 devres_log(dev, node, "ADD");
115125 BUG_ON(!list_empty(&node->entry));
116126 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);
117135 }
118136
119137 #ifdef CONFIG_DEBUG_DEVRES
....@@ -753,9 +771,31 @@
753771
754772 WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match,
755773 &devres));
756
-
757774 }
758775 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);
759799
760800 /*
761801 * Managed kmalloc/kfree
....@@ -783,9 +823,12 @@
783823 * RETURNS:
784824 * Pointer to allocated memory on success, NULL on failure.
785825 */
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)
787827 {
788828 struct devres *dr;
829
+
830
+ if (unlikely(!size))
831
+ return ZERO_SIZE_PTR;
789832
790833 /* use raw alloc_dr for kmalloc caller tracing */
791834 dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
....@@ -801,6 +844,103 @@
801844 return dr->data;
802845 }
803846 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);
804944
805945 /**
806946 * devm_kstrdup - Allocate resource managed space and
....@@ -827,6 +967,28 @@
827967 return buf;
828968 }
829969 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);
830992
831993 /**
832994 * devm_kvasprintf - Allocate resource managed space and format a string
....@@ -891,11 +1053,19 @@
8911053 *
8921054 * Free memory allocated with devm_kmalloc().
8931055 */
894
-void devm_kfree(struct device *dev, void *p)
1056
+void devm_kfree(struct device *dev, const void *p)
8951057 {
8961058 int rc;
8971059
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);
8991069 WARN_ON(rc);
9001070 }
9011071 EXPORT_SYMBOL_GPL(devm_kfree);