History

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.

Roman Gushchin committed 7 years ago

Commit b936ca61 parent 3539b9614 files · +112 −88Browse files

Showing the changes to kernel/bpf/queue_stack_maps.c (1 of 14 files). Show all

Unified · Split

kernel/bpf/queue_stack_maps.c+6−3
@@ -67,6 +67,7 @@ static int queue_stack_map_alloc_check(union bpf_attr *attr) · 66 unmodified lines
6767 static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr)
6868 {
6969 int ret, numa_node = bpf_map_attr_numa_node(attr);
70+ struct bpf_map_memory mem = {0};
7071 struct bpf_queue_stack *qs;
7172 u64 size, queue_size, cost;
7273
@@ -77,19 +78,21 @@ static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr) · 4 unmodified lines
7778
7879 cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
7980
80− ret = bpf_map_precharge_memlock(cost);
81+ ret = bpf_map_charge_init(&mem, cost);
8182 if (ret < 0)
8283 return ERR_PTR(ret);
8384
8485 qs = bpf_map_area_alloc(queue_size, numa_node);
85− if (!qs)
86+ if (!qs) {
87+ bpf_map_charge_finish(&mem);
8688 return ERR_PTR(-ENOMEM);
89+ }
8790
8891 memset(qs, 0, sizeof(*qs));
8992
9093 bpf_map_init_from_attr(&qs->map, attr);
9194
92− qs->map.memory.pages = cost;
95+ bpf_map_charge_move(&qs->map.memory, &mem);
9396 qs->size = size;
9497
9598 raw_spin_lock_init(&qs->lock);