summaryrefslogtreecommitdiffstats
path: root/kernel/bpf/arraymap.c
diff options
context:
space:
mode:
authorRoman Gushchin <guro@fb.com>2019-05-29 21:03:58 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-05-31 19:52:56 -0400
commitb936ca643ade11f265fa10e5fb71c20d9c5243f1 (patch)
treefab6cc685363f4f9901fecf6335a8d8e6974f8b3 /kernel/bpf/arraymap.c
parent3539b96e041c06e4317082816d90ec09160aeb11 (diff)
bpf: rework memlock-based memory accounting for maps
In order to unify the existing memlock charging code with the memcg-based memory accounting, which will be added later, let's rework the current scheme. Currently the following design is used: 1) .alloc() callback optionally checks if the allocation will likely succeed using bpf_map_precharge_memlock() 2) .alloc() performs actual allocations 3) .alloc() callback calculates map cost and sets map.memory.pages 4) map_create() calls bpf_map_init_memlock() which sets map.memory.user and performs actual charging; in case of failure the map is destroyed <map is in use> 1) bpf_map_free_deferred() calls bpf_map_release_memlock(), which performs uncharge and releases the user 2) .map_free() callback releases the memory The scheme can be simplified and made more robust: 1) .alloc() calculates map cost and calls bpf_map_charge_init() 2) bpf_map_charge_init() sets map.memory.user and performs actual charge 3) .alloc() performs actual allocations <map is in use> 1) .map_free() callback releases the memory 2) bpf_map_charge_finish() performs uncharge and releases the user The new scheme also allows to reuse bpf_map_charge_init()/finish() functions for memcg-based accounting. Because charges are performed before actual allocations and uncharges after freeing the memory, no bogus memory pressure can be created. In cases when the map structure is not available (e.g. it's not created yet, or is already destroyed), on-stack bpf_map_memory structure is used. The charge can be transferred with the bpf_map_charge_move() function. Signed-off-by: Roman Gushchin <guro@fb.com> Acked-by: Song Liu <songliubraving@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/arraymap.c')
-rw-r--r--kernel/bpf/arraymap.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 8fda24e78193..3552da4407d9 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -83,6 +83,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
83 u32 elem_size, index_mask, max_entries; 83 u32 elem_size, index_mask, max_entries;
84 bool unpriv = !capable(CAP_SYS_ADMIN); 84 bool unpriv = !capable(CAP_SYS_ADMIN);
85 u64 cost, array_size, mask64; 85 u64 cost, array_size, mask64;
86 struct bpf_map_memory mem;
86 struct bpf_array *array; 87 struct bpf_array *array;
87 88
88 elem_size = round_up(attr->value_size, 8); 89 elem_size = round_up(attr->value_size, 8);
@@ -125,23 +126,26 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
125 } 126 }
126 cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; 127 cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
127 128
128 ret = bpf_map_precharge_memlock(cost); 129 ret = bpf_map_charge_init(&mem, cost);
129 if (ret < 0) 130 if (ret < 0)
130 return ERR_PTR(ret); 131 return ERR_PTR(ret);
131 132
132 /* allocate all map elements and zero-initialize them */ 133 /* allocate all map elements and zero-initialize them */
133 array = bpf_map_area_alloc(array_size, numa_node); 134 array = bpf_map_area_alloc(array_size, numa_node);
134 if (!array) 135 if (!array) {
136 bpf_map_charge_finish(&mem);
135 return ERR_PTR(-ENOMEM); 137 return ERR_PTR(-ENOMEM);
138 }
136 array->index_mask = index_mask; 139 array->index_mask = index_mask;
137 array->map.unpriv_array = unpriv; 140 array->map.unpriv_array = unpriv;
138 141
139 /* copy mandatory map attributes */ 142 /* copy mandatory map attributes */
140 bpf_map_init_from_attr(&array->map, attr); 143 bpf_map_init_from_attr(&array->map, attr);
141 array->map.memory.pages = cost; 144 bpf_map_charge_move(&array->map.memory, &mem);
142 array->elem_size = elem_size; 145 array->elem_size = elem_size;
143 146
144 if (percpu && bpf_array_alloc_percpu(array)) { 147 if (percpu && bpf_array_alloc_percpu(array)) {
148 bpf_map_charge_finish(&array->map.memory);
145 bpf_map_area_free(array); 149 bpf_map_area_free(array);
146 return ERR_PTR(-ENOMEM); 150 return ERR_PTR(-ENOMEM);
147 } 151 }