mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branch 'switch to memcg-based memory accounting'
Roman Gushchin says:
====================
Currently bpf is using the memlock rlimit for the memory accounting.
This approach has its downsides and over time has created a significant
amount of problems:
1) The limit is per-user, but because most bpf operations are performed
as root, the limit has a little value.
2) It's hard to come up with a specific maximum value. Especially because
the counter is shared with non-bpf use cases (e.g. memlock()).
Any specific value is either too low and creates false failures
or is too high and useless.
3) Charging is not connected to the actual memory allocation. Bpf code
should manually calculate the estimated cost and charge the counter,
and then take care of uncharging, including all fail paths.
It adds to the code complexity and makes it easy to leak a charge.
4) There is no simple way of getting the current value of the counter.
We've used drgn for it, but it's far from being convenient.
5) Cryptic -EPERM is returned on exceeding the limit. Libbpf even had
a function to "explain" this case for users.
6) rlimits are generally considered as (at least partially) obsolete.
They do not provide a comprehensive system for the control of physical
resources: memory, cpu, io etc. All resource control developments
in the recent years were related to cgroups.
In order to overcome these problems let's switch to the memory cgroup-based
memory accounting of bpf objects. With the recent addition of the percpu
memory accounting, now it's possible to provide a comprehensive accounting
of the memory used by bpf programs and maps.
This approach has the following advantages:
1) The limit is per-cgroup and hierarchical. It's way more flexible and allows
a better control over memory usage by different workloads.
2) The actual memory consumption is taken into account. It happens automatically
on the allocation time if __GFP_ACCOUNT flags is passed. Uncharging is also
performed automatically on releasing the memory. So the code on the bpf side
becomes simpler and safer.
3) There is a simple way to get the current value and statistics.
Cgroup-based accounting adds new requirements:
1) The kernel config should have CONFIG_CGROUPS and CONFIG_MEMCG_KMEM enabled.
These options are usually enabled, maybe excluding tiny builds for embedded
devices.
2) The system should have a configured cgroup hierarchy, including reasonable
memory limits and/or guarantees. Modern systems usually delegate this task
to systemd or similar task managers.
Without meeting these requirements there are no limits on how much memory bpf
can use and a non-root user is able to hurt the system by allocating too much.
But because per-user rlimits do not provide a functional system to protect
and manage physical resources anyway, anyone who seriously depends on it,
should use cgroups.
When a bpf map is created, the memory cgroup of the process which creates
the map is recorded. Subsequently all memory allocation related to the bpf map
are charged to the same cgroup. It includes allocations made from interrupts
and by any processes. Bpf program memory is charged to the memory cgroup of
a process which loads the program.
The patchset consists of the following parts:
1) 4 mm patches are required on the mm side, otherwise vmallocs cannot be mapped
to userspace
2) memcg-based accounting for various bpf objects: progs and maps
3) removal of the rlimit-based accounting
4) removal of rlimit adjustments in userspace samples
v9:
- always charge the saved memory cgroup, by Daniel, Toke and Alexei
- added bpf_map_kzalloc()
- rebase and minor fixes
v8:
- extended the cover letter to be more clear on new requirements, by Daniel
- an approximate value is provided by map memlock info, by Alexei
v7:
- introduced bpf_map_kmalloc_node() and bpf_map_alloc_percpu(), by Alexei
- switched allocations made from an interrupt context to new helpers,
by Daniel
- rebase and minor fixes
v6:
- rebased to the latest version of the remote charging API
- fixed signatures, added acks
v5:
- rebased to the latest version of the remote charging API
- implemented kmem accounting from an interrupt context, by Shakeel
- rebased to latest changes in mm allowed to map vmallocs to userspace
- fixed a build issue in kselftests, by Alexei
- fixed a use-after-free bug in bpf_map_free_deferred()
- added bpf line info coverage, by Shakeel
- split bpf map charging preparations into a separate patch
v4:
- covered allocations made from an interrupt context, by Daniel
- added some clarifications to the cover letter
v3:
- droped the userspace part for further discussions/refinements,
by Andrii and Song
v2:
- fixed build issue, caused by the remaining rlimit-based accounting
for sockhash maps
====================
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
@@ -657,7 +657,7 @@ int __set_page_dirty_buffers(struct page *page)
|
||||
} while (bh != head);
|
||||
}
|
||||
/*
|
||||
* Lock out page->mem_cgroup migration to keep PageDirty
|
||||
* Lock out page's memcg migration to keep PageDirty
|
||||
* synchronized with per-memcg dirty page counters.
|
||||
*/
|
||||
lock_page_memcg(page);
|
||||
|
||||
@@ -650,7 +650,7 @@ iomap_set_page_dirty(struct page *page)
|
||||
return !TestSetPageDirty(page);
|
||||
|
||||
/*
|
||||
* Lock out page->mem_cgroup migration to keep PageDirty
|
||||
* Lock out page's memcg migration to keep PageDirty
|
||||
* synchronized with per-memcg dirty page counters.
|
||||
*/
|
||||
lock_page_memcg(page);
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct bpf_verifier_env;
|
||||
struct bpf_verifier_log;
|
||||
@@ -37,6 +39,7 @@ struct bpf_iter_aux_info;
|
||||
struct bpf_local_storage;
|
||||
struct bpf_local_storage_map;
|
||||
struct kobject;
|
||||
struct mem_cgroup;
|
||||
|
||||
extern struct idr btf_idr;
|
||||
extern spinlock_t btf_idr_lock;
|
||||
@@ -135,11 +138,6 @@ struct bpf_map_ops {
|
||||
const struct bpf_iter_seq_info *iter_seq_info;
|
||||
};
|
||||
|
||||
struct bpf_map_memory {
|
||||
u32 pages;
|
||||
struct user_struct *user;
|
||||
};
|
||||
|
||||
struct bpf_map {
|
||||
/* The first two cachelines with read-mostly members of which some
|
||||
* are also accessed in fast-path (e.g. ops, max_entries).
|
||||
@@ -160,7 +158,9 @@ struct bpf_map {
|
||||
u32 btf_key_type_id;
|
||||
u32 btf_value_type_id;
|
||||
struct btf *btf;
|
||||
struct bpf_map_memory memory;
|
||||
#ifdef CONFIG_MEMCG_KMEM
|
||||
struct mem_cgroup *memcg;
|
||||
#endif
|
||||
char name[BPF_OBJ_NAME_LEN];
|
||||
u32 btf_vmlinux_value_type_id;
|
||||
bool bypass_spec_v1;
|
||||
@@ -1202,8 +1202,6 @@ void bpf_prog_sub(struct bpf_prog *prog, int i);
|
||||
void bpf_prog_inc(struct bpf_prog *prog);
|
||||
struct bpf_prog * __must_check bpf_prog_inc_not_zero(struct bpf_prog *prog);
|
||||
void bpf_prog_put(struct bpf_prog *prog);
|
||||
int __bpf_prog_charge(struct user_struct *user, u32 pages);
|
||||
void __bpf_prog_uncharge(struct user_struct *user, u32 pages);
|
||||
void __bpf_free_used_maps(struct bpf_prog_aux *aux,
|
||||
struct bpf_map **used_maps, u32 len);
|
||||
|
||||
@@ -1218,12 +1216,6 @@ void bpf_map_inc_with_uref(struct bpf_map *map);
|
||||
struct bpf_map * __must_check bpf_map_inc_not_zero(struct bpf_map *map);
|
||||
void bpf_map_put_with_uref(struct bpf_map *map);
|
||||
void bpf_map_put(struct bpf_map *map);
|
||||
int bpf_map_charge_memlock(struct bpf_map *map, u32 pages);
|
||||
void bpf_map_uncharge_memlock(struct bpf_map *map, u32 pages);
|
||||
int bpf_map_charge_init(struct bpf_map_memory *mem, u64 size);
|
||||
void bpf_map_charge_finish(struct bpf_map_memory *mem);
|
||||
void bpf_map_charge_move(struct bpf_map_memory *dst,
|
||||
struct bpf_map_memory *src);
|
||||
void *bpf_map_area_alloc(u64 size, int numa_node);
|
||||
void *bpf_map_area_mmapable_alloc(u64 size, int numa_node);
|
||||
void bpf_map_area_free(void *base);
|
||||
@@ -1240,6 +1232,34 @@ int generic_map_delete_batch(struct bpf_map *map,
|
||||
struct bpf_map *bpf_map_get_curr_or_next(u32 *id);
|
||||
struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id);
|
||||
|
||||
#ifdef CONFIG_MEMCG_KMEM
|
||||
void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
|
||||
int node);
|
||||
void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags);
|
||||
void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
|
||||
size_t align, gfp_t flags);
|
||||
#else
|
||||
static inline void *
|
||||
bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
|
||||
int node)
|
||||
{
|
||||
return kmalloc_node(size, flags, node);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
|
||||
{
|
||||
return kzalloc(size, flags);
|
||||
}
|
||||
|
||||
static inline void __percpu *
|
||||
bpf_map_alloc_percpu(const struct bpf_map *map, size_t size, size_t align,
|
||||
gfp_t flags)
|
||||
{
|
||||
return __alloc_percpu_gfp(size, align, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern int sysctl_unprivileged_bpf_disabled;
|
||||
|
||||
static inline bool bpf_allow_ptr_leaks(void)
|
||||
@@ -1490,15 +1510,6 @@ bpf_prog_inc_not_zero(struct bpf_prog *prog)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int __bpf_prog_charge(struct user_struct *user, u32 pages)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
|
||||
const struct bpf_link_ops *ops,
|
||||
struct bpf_prog *prog)
|
||||
|
||||
@@ -343,6 +343,175 @@ struct mem_cgroup {
|
||||
|
||||
extern struct mem_cgroup *root_mem_cgroup;
|
||||
|
||||
enum page_memcg_data_flags {
|
||||
/* page->memcg_data is a pointer to an objcgs vector */
|
||||
MEMCG_DATA_OBJCGS = (1UL << 0),
|
||||
/* page has been accounted as a non-slab kernel page */
|
||||
MEMCG_DATA_KMEM = (1UL << 1),
|
||||
/* the next bit after the last actual flag */
|
||||
__NR_MEMCG_DATA_FLAGS = (1UL << 2),
|
||||
};
|
||||
|
||||
#define MEMCG_DATA_FLAGS_MASK (__NR_MEMCG_DATA_FLAGS - 1)
|
||||
|
||||
/*
|
||||
* page_memcg - get the memory cgroup associated with a page
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Returns a pointer to the memory cgroup associated with the page,
|
||||
* or NULL. This function assumes that the page is known to have a
|
||||
* proper memory cgroup pointer. It's not safe to call this function
|
||||
* against some type of pages, e.g. slab pages or ex-slab pages.
|
||||
*
|
||||
* Any of the following ensures page and memcg binding stability:
|
||||
* - the page lock
|
||||
* - LRU isolation
|
||||
* - lock_page_memcg()
|
||||
* - exclusive reference
|
||||
*/
|
||||
static inline struct mem_cgroup *page_memcg(struct page *page)
|
||||
{
|
||||
unsigned long memcg_data = page->memcg_data;
|
||||
|
||||
VM_BUG_ON_PAGE(PageSlab(page), page);
|
||||
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_OBJCGS, page);
|
||||
|
||||
return (struct mem_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* page_memcg_rcu - locklessly get the memory cgroup associated with a page
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Returns a pointer to the memory cgroup associated with the page,
|
||||
* or NULL. This function assumes that the page is known to have a
|
||||
* proper memory cgroup pointer. It's not safe to call this function
|
||||
* against some type of pages, e.g. slab pages or ex-slab pages.
|
||||
*/
|
||||
static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
|
||||
{
|
||||
VM_BUG_ON_PAGE(PageSlab(page), page);
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
|
||||
return (struct mem_cgroup *)(READ_ONCE(page->memcg_data) &
|
||||
~MEMCG_DATA_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* page_memcg_check - get the memory cgroup associated with a page
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Returns a pointer to the memory cgroup associated with the page,
|
||||
* or NULL. This function unlike page_memcg() can take any page
|
||||
* as an argument. It has to be used in cases when it's not known if a page
|
||||
* has an associated memory cgroup pointer or an object cgroups vector.
|
||||
*
|
||||
* Any of the following ensures page and memcg binding stability:
|
||||
* - the page lock
|
||||
* - LRU isolation
|
||||
* - lock_page_memcg()
|
||||
* - exclusive reference
|
||||
*/
|
||||
static inline struct mem_cgroup *page_memcg_check(struct page *page)
|
||||
{
|
||||
/*
|
||||
* Because page->memcg_data might be changed asynchronously
|
||||
* for slab pages, READ_ONCE() should be used here.
|
||||
*/
|
||||
unsigned long memcg_data = READ_ONCE(page->memcg_data);
|
||||
|
||||
if (memcg_data & MEMCG_DATA_OBJCGS)
|
||||
return NULL;
|
||||
|
||||
return (struct mem_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* PageMemcgKmem - check if the page has MemcgKmem flag set
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Checks if the page has MemcgKmem flag set. The caller must ensure that
|
||||
* the page has an associated memory cgroup. It's not safe to call this function
|
||||
* against some types of pages, e.g. slab pages.
|
||||
*/
|
||||
static inline bool PageMemcgKmem(struct page *page)
|
||||
{
|
||||
VM_BUG_ON_PAGE(page->memcg_data & MEMCG_DATA_OBJCGS, page);
|
||||
return page->memcg_data & MEMCG_DATA_KMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MEMCG_KMEM
|
||||
/*
|
||||
* page_objcgs - get the object cgroups vector associated with a page
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Returns a pointer to the object cgroups vector associated with the page,
|
||||
* or NULL. This function assumes that the page is known to have an
|
||||
* associated object cgroups vector. It's not safe to call this function
|
||||
* against pages, which might have an associated memory cgroup: e.g.
|
||||
* kernel stack pages.
|
||||
*/
|
||||
static inline struct obj_cgroup **page_objcgs(struct page *page)
|
||||
{
|
||||
unsigned long memcg_data = READ_ONCE(page->memcg_data);
|
||||
|
||||
VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS), page);
|
||||
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
|
||||
|
||||
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* page_objcgs_check - get the object cgroups vector associated with a page
|
||||
* @page: a pointer to the page struct
|
||||
*
|
||||
* Returns a pointer to the object cgroups vector associated with the page,
|
||||
* or NULL. This function is safe to use if the page can be directly associated
|
||||
* with a memory cgroup.
|
||||
*/
|
||||
static inline struct obj_cgroup **page_objcgs_check(struct page *page)
|
||||
{
|
||||
unsigned long memcg_data = READ_ONCE(page->memcg_data);
|
||||
|
||||
if (!memcg_data || !(memcg_data & MEMCG_DATA_OBJCGS))
|
||||
return NULL;
|
||||
|
||||
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
|
||||
|
||||
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* set_page_objcgs - associate a page with a object cgroups vector
|
||||
* @page: a pointer to the page struct
|
||||
* @objcgs: a pointer to the object cgroups vector
|
||||
*
|
||||
* Atomically associates a page with a vector of object cgroups.
|
||||
*/
|
||||
static inline bool set_page_objcgs(struct page *page,
|
||||
struct obj_cgroup **objcgs)
|
||||
{
|
||||
return !cmpxchg(&page->memcg_data, 0, (unsigned long)objcgs |
|
||||
MEMCG_DATA_OBJCGS);
|
||||
}
|
||||
#else
|
||||
static inline struct obj_cgroup **page_objcgs(struct page *page)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct obj_cgroup **page_objcgs_check(struct page *page)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool set_page_objcgs(struct page *page,
|
||||
struct obj_cgroup **objcgs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __always_inline bool memcg_stat_item_in_bytes(int idx)
|
||||
{
|
||||
if (idx == MEMCG_PERCPU_B)
|
||||
@@ -743,15 +912,19 @@ static inline void mod_memcg_state(struct mem_cgroup *memcg,
|
||||
static inline void __mod_memcg_page_state(struct page *page,
|
||||
int idx, int val)
|
||||
{
|
||||
if (page->mem_cgroup)
|
||||
__mod_memcg_state(page->mem_cgroup, idx, val);
|
||||
struct mem_cgroup *memcg = page_memcg(page);
|
||||
|
||||
if (memcg)
|
||||
__mod_memcg_state(memcg, idx, val);
|
||||
}
|
||||
|
||||
static inline void mod_memcg_page_state(struct page *page,
|
||||
int idx, int val)
|
||||
{
|
||||
if (page->mem_cgroup)
|
||||
mod_memcg_state(page->mem_cgroup, idx, val);
|
||||
struct mem_cgroup *memcg = page_memcg(page);
|
||||
|
||||
if (memcg)
|
||||
mod_memcg_state(memcg, idx, val);
|
||||
}
|
||||
|
||||
static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
|
||||
@@ -834,16 +1007,17 @@ static inline void __mod_lruvec_page_state(struct page *page,
|
||||
enum node_stat_item idx, int val)
|
||||
{
|
||||
struct page *head = compound_head(page); /* rmap on tail pages */
|
||||
struct mem_cgroup *memcg = page_memcg(head);
|
||||
pg_data_t *pgdat = page_pgdat(page);
|
||||
struct lruvec *lruvec;
|
||||
|
||||
/* Untracked pages have no memcg, no lruvec. Update only the node */
|
||||
if (!head->mem_cgroup) {
|
||||
if (!memcg) {
|
||||
__mod_node_page_state(pgdat, idx, val);
|
||||
return;
|
||||
}
|
||||
|
||||
lruvec = mem_cgroup_lruvec(head->mem_cgroup, pgdat);
|
||||
lruvec = mem_cgroup_lruvec(memcg, pgdat);
|
||||
__mod_lruvec_state(lruvec, idx, val);
|
||||
}
|
||||
|
||||
@@ -878,8 +1052,10 @@ static inline void count_memcg_events(struct mem_cgroup *memcg,
|
||||
static inline void count_memcg_page_event(struct page *page,
|
||||
enum vm_event_item idx)
|
||||
{
|
||||
if (page->mem_cgroup)
|
||||
count_memcg_events(page->mem_cgroup, idx, 1);
|
||||
struct mem_cgroup *memcg = page_memcg(page);
|
||||
|
||||
if (memcg)
|
||||
count_memcg_events(memcg, idx, 1);
|
||||
}
|
||||
|
||||
static inline void count_memcg_event_mm(struct mm_struct *mm,
|
||||
@@ -941,6 +1117,27 @@ void mem_cgroup_split_huge_fixup(struct page *head);
|
||||
|
||||
struct mem_cgroup;
|
||||
|
||||
static inline struct mem_cgroup *page_memcg(struct page *page)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
|
||||
{
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct mem_cgroup *page_memcg_check(struct page *page)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool PageMemcgKmem(struct page *page)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
|
||||
{
|
||||
return true;
|
||||
@@ -1430,7 +1627,7 @@ static inline void mem_cgroup_track_foreign_dirty(struct page *page,
|
||||
if (mem_cgroup_disabled())
|
||||
return;
|
||||
|
||||
if (unlikely(&page->mem_cgroup->css != wb->memcg_css))
|
||||
if (unlikely(&page_memcg(page)->css != wb->memcg_css))
|
||||
mem_cgroup_track_foreign_dirty_slowpath(page, wb);
|
||||
}
|
||||
|
||||
|
||||
@@ -1484,28 +1484,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MEMCG
|
||||
static inline struct mem_cgroup *page_memcg(struct page *page)
|
||||
{
|
||||
return page->mem_cgroup;
|
||||
}
|
||||
static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
|
||||
{
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
return READ_ONCE(page->mem_cgroup);
|
||||
}
|
||||
#else
|
||||
static inline struct mem_cgroup *page_memcg(struct page *page)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
|
||||
{
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some inline functions in vmstat.h depend on page_zone()
|
||||
*/
|
||||
|
||||
@@ -199,10 +199,7 @@ struct page {
|
||||
atomic_t _refcount;
|
||||
|
||||
#ifdef CONFIG_MEMCG
|
||||
union {
|
||||
struct mem_cgroup *mem_cgroup;
|
||||
struct obj_cgroup **obj_cgroups;
|
||||
};
|
||||
unsigned long memcg_data;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
@@ -715,9 +715,8 @@ PAGEFLAG_FALSE(DoubleMap)
|
||||
#define PAGE_MAPCOUNT_RESERVE -128
|
||||
#define PG_buddy 0x00000080
|
||||
#define PG_offline 0x00000100
|
||||
#define PG_kmemcg 0x00000200
|
||||
#define PG_table 0x00000400
|
||||
#define PG_guard 0x00000800
|
||||
#define PG_table 0x00000200
|
||||
#define PG_guard 0x00000400
|
||||
|
||||
#define PageType(page, flag) \
|
||||
((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
|
||||
@@ -768,12 +767,6 @@ PAGE_TYPE_OPS(Buddy, buddy)
|
||||
*/
|
||||
PAGE_TYPE_OPS(Offline, offline)
|
||||
|
||||
/*
|
||||
* If kmemcg is enabled, the buddy allocator will set PageKmemcg() on
|
||||
* pages allocated with __GFP_ACCOUNT. It gets cleared on page free.
|
||||
*/
|
||||
PAGE_TYPE_OPS(Kmemcg, kmemcg)
|
||||
|
||||
/*
|
||||
* Marks pages in use as page tables.
|
||||
*/
|
||||
|
||||
@@ -257,7 +257,7 @@ TRACE_EVENT(track_foreign_dirty,
|
||||
__entry->ino = inode ? inode->i_ino : 0;
|
||||
__entry->memcg_id = wb->memcg_css->id;
|
||||
__entry->cgroup_ino = __trace_wb_assign_cgroup(wb);
|
||||
__entry->page_cgroup_ino = cgroup_ino(page->mem_cgroup->css.cgroup);
|
||||
__entry->page_cgroup_ino = cgroup_ino(page_memcg(page)->css.cgroup);
|
||||
),
|
||||
|
||||
TP_printk("bdi %s[%llu]: ino=%lu memcg_id=%u cgroup_ino=%lu page_cgroup_ino=%lu",
|
||||
|
||||
@@ -34,8 +34,8 @@ static int bpf_array_alloc_percpu(struct bpf_array *array)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array->map.max_entries; i++) {
|
||||
ptr = __alloc_percpu_gfp(array->elem_size, 8,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
ptr = bpf_map_alloc_percpu(&array->map, array->elem_size, 8,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
if (!ptr) {
|
||||
bpf_array_free_percpu(array);
|
||||
return -ENOMEM;
|
||||
@@ -81,11 +81,10 @@ int array_map_alloc_check(union bpf_attr *attr)
|
||||
static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
|
||||
int ret, numa_node = bpf_map_attr_numa_node(attr);
|
||||
int numa_node = bpf_map_attr_numa_node(attr);
|
||||
u32 elem_size, index_mask, max_entries;
|
||||
bool bypass_spec_v1 = bpf_bypass_spec_v1();
|
||||
u64 cost, array_size, mask64;
|
||||
struct bpf_map_memory mem;
|
||||
u64 array_size, mask64;
|
||||
struct bpf_array *array;
|
||||
|
||||
elem_size = round_up(attr->value_size, 8);
|
||||
@@ -126,44 +125,29 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure there is no u32 overflow later in round_up() */
|
||||
cost = array_size;
|
||||
if (percpu)
|
||||
cost += (u64)attr->max_entries * elem_size * num_possible_cpus();
|
||||
|
||||
ret = bpf_map_charge_init(&mem, cost);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* allocate all map elements and zero-initialize them */
|
||||
if (attr->map_flags & BPF_F_MMAPABLE) {
|
||||
void *data;
|
||||
|
||||
/* kmalloc'ed memory can't be mmap'ed, use explicit vmalloc */
|
||||
data = bpf_map_area_mmapable_alloc(array_size, numa_node);
|
||||
if (!data) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
if (!data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
array = data + PAGE_ALIGN(sizeof(struct bpf_array))
|
||||
- offsetof(struct bpf_array, value);
|
||||
} else {
|
||||
array = bpf_map_area_alloc(array_size, numa_node);
|
||||
}
|
||||
if (!array) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
if (!array)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
array->index_mask = index_mask;
|
||||
array->map.bypass_spec_v1 = bypass_spec_v1;
|
||||
|
||||
/* copy mandatory map attributes */
|
||||
bpf_map_init_from_attr(&array->map, attr);
|
||||
bpf_map_charge_move(&array->map.memory, &mem);
|
||||
array->elem_size = elem_size;
|
||||
|
||||
if (percpu && bpf_array_alloc_percpu(array)) {
|
||||
bpf_map_charge_finish(&array->map.memory);
|
||||
bpf_map_area_free(array);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@@ -1018,7 +1002,7 @@ static struct bpf_map *prog_array_map_alloc(union bpf_attr *attr)
|
||||
struct bpf_array_aux *aux;
|
||||
struct bpf_map *map;
|
||||
|
||||
aux = kzalloc(sizeof(*aux), GFP_KERNEL);
|
||||
aux = kzalloc(sizeof(*aux), GFP_KERNEL_ACCOUNT);
|
||||
if (!aux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ bpf_selem_alloc(struct bpf_local_storage_map *smap, void *owner,
|
||||
if (charge_mem && mem_charge(smap, owner, smap->elem_size))
|
||||
return NULL;
|
||||
|
||||
selem = kzalloc(smap->elem_size, GFP_ATOMIC | __GFP_NOWARN);
|
||||
selem = bpf_map_kzalloc(&smap->map, smap->elem_size,
|
||||
GFP_ATOMIC | __GFP_NOWARN);
|
||||
if (selem) {
|
||||
if (value)
|
||||
memcpy(SDATA(selem)->data, value, smap->map.value_size);
|
||||
@@ -264,7 +265,8 @@ int bpf_local_storage_alloc(void *owner,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
storage = kzalloc(sizeof(*storage), GFP_ATOMIC | __GFP_NOWARN);
|
||||
storage = bpf_map_kzalloc(&smap->map, sizeof(*storage),
|
||||
GFP_ATOMIC | __GFP_NOWARN);
|
||||
if (!storage) {
|
||||
err = -ENOMEM;
|
||||
goto uncharge;
|
||||
@@ -543,10 +545,8 @@ struct bpf_local_storage_map *bpf_local_storage_map_alloc(union bpf_attr *attr)
|
||||
struct bpf_local_storage_map *smap;
|
||||
unsigned int i;
|
||||
u32 nbuckets;
|
||||
u64 cost;
|
||||
int ret;
|
||||
|
||||
smap = kzalloc(sizeof(*smap), GFP_USER | __GFP_NOWARN);
|
||||
smap = kzalloc(sizeof(*smap), GFP_USER | __GFP_NOWARN | __GFP_ACCOUNT);
|
||||
if (!smap)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
bpf_map_init_from_attr(&smap->map, attr);
|
||||
@@ -555,18 +555,10 @@ struct bpf_local_storage_map *bpf_local_storage_map_alloc(union bpf_attr *attr)
|
||||
/* Use at least 2 buckets, select_bucket() is undefined behavior with 1 bucket */
|
||||
nbuckets = max_t(u32, 2, nbuckets);
|
||||
smap->bucket_log = ilog2(nbuckets);
|
||||
cost = sizeof(*smap->buckets) * nbuckets + sizeof(*smap);
|
||||
|
||||
ret = bpf_map_charge_init(&smap->map.memory, cost);
|
||||
if (ret < 0) {
|
||||
kfree(smap);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
smap->buckets = kvcalloc(sizeof(*smap->buckets), nbuckets,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
GFP_USER | __GFP_NOWARN | __GFP_ACCOUNT);
|
||||
if (!smap->buckets) {
|
||||
bpf_map_charge_finish(&smap->map.memory);
|
||||
kfree(smap);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
@@ -548,12 +548,10 @@ static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr)
|
||||
static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
const struct bpf_struct_ops *st_ops;
|
||||
size_t map_total_size, st_map_size;
|
||||
size_t st_map_size;
|
||||
struct bpf_struct_ops_map *st_map;
|
||||
const struct btf_type *t, *vt;
|
||||
struct bpf_map_memory mem;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
if (!bpf_capable())
|
||||
return ERR_PTR(-EPERM);
|
||||
@@ -573,20 +571,11 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
|
||||
* struct bpf_struct_ops_tcp_congestions_ops
|
||||
*/
|
||||
(vt->size - sizeof(struct bpf_struct_ops_value));
|
||||
map_total_size = st_map_size +
|
||||
/* uvalue */
|
||||
sizeof(vt->size) +
|
||||
/* struct bpf_progs **progs */
|
||||
btf_type_vlen(t) * sizeof(struct bpf_prog *);
|
||||
err = bpf_map_charge_init(&mem, map_total_size);
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
st_map = bpf_map_area_alloc(st_map_size, NUMA_NO_NODE);
|
||||
if (!st_map) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
if (!st_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
st_map->st_ops = st_ops;
|
||||
map = &st_map->map;
|
||||
|
||||
@@ -597,14 +586,12 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
|
||||
st_map->image = bpf_jit_alloc_exec(PAGE_SIZE);
|
||||
if (!st_map->uvalue || !st_map->progs || !st_map->image) {
|
||||
bpf_struct_ops_map_free(map);
|
||||
bpf_map_charge_finish(&mem);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
mutex_init(&st_map->lock);
|
||||
set_vm_flush_reset_perms(st_map->image);
|
||||
bpf_map_init_from_attr(map, attr);
|
||||
bpf_map_charge_move(&map->memory, &mem);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
|
||||
|
||||
struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flags)
|
||||
{
|
||||
gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | gfp_extra_flags;
|
||||
gfp_t gfp_flags = GFP_KERNEL_ACCOUNT | __GFP_ZERO | gfp_extra_flags;
|
||||
struct bpf_prog_aux *aux;
|
||||
struct bpf_prog *fp;
|
||||
|
||||
@@ -86,7 +86,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
|
||||
aux = kzalloc(sizeof(*aux), GFP_KERNEL | gfp_extra_flags);
|
||||
aux = kzalloc(sizeof(*aux), GFP_KERNEL_ACCOUNT | gfp_extra_flags);
|
||||
if (aux == NULL) {
|
||||
vfree(fp);
|
||||
return NULL;
|
||||
@@ -106,7 +106,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag
|
||||
|
||||
struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags)
|
||||
{
|
||||
gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | gfp_extra_flags;
|
||||
gfp_t gfp_flags = GFP_KERNEL_ACCOUNT | __GFP_ZERO | gfp_extra_flags;
|
||||
struct bpf_prog *prog;
|
||||
int cpu;
|
||||
|
||||
@@ -138,7 +138,7 @@ int bpf_prog_alloc_jited_linfo(struct bpf_prog *prog)
|
||||
|
||||
prog->aux->jited_linfo = kcalloc(prog->aux->nr_linfo,
|
||||
sizeof(*prog->aux->jited_linfo),
|
||||
GFP_KERNEL | __GFP_NOWARN);
|
||||
GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
|
||||
if (!prog->aux->jited_linfo)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -219,25 +219,17 @@ void bpf_prog_free_linfo(struct bpf_prog *prog)
|
||||
struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
|
||||
gfp_t gfp_extra_flags)
|
||||
{
|
||||
gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO | gfp_extra_flags;
|
||||
gfp_t gfp_flags = GFP_KERNEL_ACCOUNT | __GFP_ZERO | gfp_extra_flags;
|
||||
struct bpf_prog *fp;
|
||||
u32 pages, delta;
|
||||
int ret;
|
||||
u32 pages;
|
||||
|
||||
size = round_up(size, PAGE_SIZE);
|
||||
pages = size / PAGE_SIZE;
|
||||
if (pages <= fp_old->pages)
|
||||
return fp_old;
|
||||
|
||||
delta = pages - fp_old->pages;
|
||||
ret = __bpf_prog_charge(fp_old->aux->user, delta);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
fp = __vmalloc(size, gfp_flags);
|
||||
if (fp == NULL) {
|
||||
__bpf_prog_uncharge(fp_old->aux->user, delta);
|
||||
} else {
|
||||
if (fp) {
|
||||
memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
|
||||
fp->pages = pages;
|
||||
fp->aux->prog = fp;
|
||||
|
||||
@@ -84,8 +84,6 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
|
||||
u32 value_size = attr->value_size;
|
||||
struct bpf_cpu_map *cmap;
|
||||
int err = -ENOMEM;
|
||||
u64 cost;
|
||||
int ret;
|
||||
|
||||
if (!bpf_capable())
|
||||
return ERR_PTR(-EPERM);
|
||||
@@ -97,7 +95,7 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
|
||||
attr->map_flags & ~BPF_F_NUMA_NODE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cmap = kzalloc(sizeof(*cmap), GFP_USER);
|
||||
cmap = kzalloc(sizeof(*cmap), GFP_USER | __GFP_ACCOUNT);
|
||||
if (!cmap)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -109,26 +107,14 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr)
|
||||
goto free_cmap;
|
||||
}
|
||||
|
||||
/* make sure page count doesn't overflow */
|
||||
cost = (u64) cmap->map.max_entries * sizeof(struct bpf_cpu_map_entry *);
|
||||
|
||||
/* Notice returns -EPERM on if map size is larger than memlock limit */
|
||||
ret = bpf_map_charge_init(&cmap->map.memory, cost);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
goto free_cmap;
|
||||
}
|
||||
|
||||
/* Alloc array for possible remote "destination" CPUs */
|
||||
cmap->cpu_map = bpf_map_area_alloc(cmap->map.max_entries *
|
||||
sizeof(struct bpf_cpu_map_entry *),
|
||||
cmap->map.numa_node);
|
||||
if (!cmap->cpu_map)
|
||||
goto free_charge;
|
||||
goto free_cmap;
|
||||
|
||||
return &cmap->map;
|
||||
free_charge:
|
||||
bpf_map_charge_finish(&cmap->map.memory);
|
||||
free_cmap:
|
||||
kfree(cmap);
|
||||
return ERR_PTR(err);
|
||||
@@ -412,7 +398,8 @@ static int __cpu_map_load_bpf_program(struct bpf_cpu_map_entry *rcpu, int fd)
|
||||
}
|
||||
|
||||
static struct bpf_cpu_map_entry *
|
||||
__cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
|
||||
__cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
|
||||
u32 cpu)
|
||||
{
|
||||
int numa, err, i, fd = value->bpf_prog.fd;
|
||||
gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
|
||||
@@ -422,13 +409,13 @@ __cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
|
||||
/* Have map->numa_node, but choose node of redirect target CPU */
|
||||
numa = cpu_to_node(cpu);
|
||||
|
||||
rcpu = kzalloc_node(sizeof(*rcpu), gfp, numa);
|
||||
rcpu = bpf_map_kmalloc_node(map, sizeof(*rcpu), gfp | __GFP_ZERO, numa);
|
||||
if (!rcpu)
|
||||
return NULL;
|
||||
|
||||
/* Alloc percpu bulkq */
|
||||
rcpu->bulkq = __alloc_percpu_gfp(sizeof(*rcpu->bulkq),
|
||||
sizeof(void *), gfp);
|
||||
rcpu->bulkq = bpf_map_alloc_percpu(map, sizeof(*rcpu->bulkq),
|
||||
sizeof(void *), gfp);
|
||||
if (!rcpu->bulkq)
|
||||
goto free_rcu;
|
||||
|
||||
@@ -438,7 +425,8 @@ __cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
|
||||
}
|
||||
|
||||
/* Alloc queue */
|
||||
rcpu->queue = kzalloc_node(sizeof(*rcpu->queue), gfp, numa);
|
||||
rcpu->queue = bpf_map_kmalloc_node(map, sizeof(*rcpu->queue), gfp,
|
||||
numa);
|
||||
if (!rcpu->queue)
|
||||
goto free_bulkq;
|
||||
|
||||
@@ -447,7 +435,7 @@ __cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
|
||||
goto free_queue;
|
||||
|
||||
rcpu->cpu = cpu;
|
||||
rcpu->map_id = map_id;
|
||||
rcpu->map_id = map->id;
|
||||
rcpu->value.qsize = value->qsize;
|
||||
|
||||
if (fd > 0 && __cpu_map_load_bpf_program(rcpu, fd))
|
||||
@@ -455,7 +443,8 @@ __cpu_map_entry_alloc(struct bpf_cpumap_val *value, u32 cpu, int map_id)
|
||||
|
||||
/* Setup kthread */
|
||||
rcpu->kthread = kthread_create_on_node(cpu_map_kthread_run, rcpu, numa,
|
||||
"cpumap/%d/map:%d", cpu, map_id);
|
||||
"cpumap/%d/map:%d", cpu,
|
||||
map->id);
|
||||
if (IS_ERR(rcpu->kthread))
|
||||
goto free_prog;
|
||||
|
||||
@@ -571,7 +560,7 @@ static int cpu_map_update_elem(struct bpf_map *map, void *key, void *value,
|
||||
rcpu = NULL; /* Same as deleting */
|
||||
} else {
|
||||
/* Updating qsize cause re-allocation of bpf_cpu_map_entry */
|
||||
rcpu = __cpu_map_entry_alloc(&cpumap_value, key_cpu, map->id);
|
||||
rcpu = __cpu_map_entry_alloc(map, &cpumap_value, key_cpu);
|
||||
if (!rcpu)
|
||||
return -ENOMEM;
|
||||
rcpu->cmap = cmap;
|
||||
|
||||
@@ -109,8 +109,6 @@ static inline struct hlist_head *dev_map_index_hash(struct bpf_dtab *dtab,
|
||||
static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
|
||||
{
|
||||
u32 valsize = attr->value_size;
|
||||
u64 cost = 0;
|
||||
int err;
|
||||
|
||||
/* check sanity of attributes. 2 value sizes supported:
|
||||
* 4 bytes: ifindex
|
||||
@@ -135,21 +133,13 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
|
||||
|
||||
if (!dtab->n_buckets) /* Overflow check */
|
||||
return -EINVAL;
|
||||
cost += (u64) sizeof(struct hlist_head) * dtab->n_buckets;
|
||||
} else {
|
||||
cost += (u64) dtab->map.max_entries * sizeof(struct bpf_dtab_netdev *);
|
||||
}
|
||||
|
||||
/* if map size is larger than memlock limit, reject it */
|
||||
err = bpf_map_charge_init(&dtab->map.memory, cost);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
if (attr->map_type == BPF_MAP_TYPE_DEVMAP_HASH) {
|
||||
dtab->dev_index_head = dev_map_create_hash(dtab->n_buckets,
|
||||
dtab->map.numa_node);
|
||||
if (!dtab->dev_index_head)
|
||||
goto free_charge;
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&dtab->index_lock);
|
||||
} else {
|
||||
@@ -157,14 +147,10 @@ static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr)
|
||||
sizeof(struct bpf_dtab_netdev *),
|
||||
dtab->map.numa_node);
|
||||
if (!dtab->netdev_map)
|
||||
goto free_charge;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_charge:
|
||||
bpf_map_charge_finish(&dtab->map.memory);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
|
||||
@@ -175,7 +161,7 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
dtab = kzalloc(sizeof(*dtab), GFP_USER);
|
||||
dtab = kzalloc(sizeof(*dtab), GFP_USER | __GFP_ACCOUNT);
|
||||
if (!dtab)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -602,8 +588,9 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net,
|
||||
struct bpf_prog *prog = NULL;
|
||||
struct bpf_dtab_netdev *dev;
|
||||
|
||||
dev = kmalloc_node(sizeof(*dev), GFP_ATOMIC | __GFP_NOWARN,
|
||||
dtab->map.numa_node);
|
||||
dev = bpf_map_kmalloc_node(&dtab->map, sizeof(*dev),
|
||||
GFP_ATOMIC | __GFP_NOWARN,
|
||||
dtab->map.numa_node);
|
||||
if (!dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
||||
@@ -292,7 +292,8 @@ static int prealloc_init(struct bpf_htab *htab)
|
||||
u32 size = round_up(htab->map.value_size, 8);
|
||||
void __percpu *pptr;
|
||||
|
||||
pptr = __alloc_percpu_gfp(size, 8, GFP_USER | __GFP_NOWARN);
|
||||
pptr = bpf_map_alloc_percpu(&htab->map, size, 8,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
if (!pptr)
|
||||
goto free_elems;
|
||||
htab_elem_set_ptr(get_htab_elem(htab, i), htab->map.key_size,
|
||||
@@ -346,8 +347,8 @@ static int alloc_extra_elems(struct bpf_htab *htab)
|
||||
struct pcpu_freelist_node *l;
|
||||
int cpu;
|
||||
|
||||
pptr = __alloc_percpu_gfp(sizeof(struct htab_elem *), 8,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
pptr = bpf_map_alloc_percpu(&htab->map, sizeof(struct htab_elem *), 8,
|
||||
GFP_USER | __GFP_NOWARN);
|
||||
if (!pptr)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -442,9 +443,8 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
|
||||
bool prealloc = !(attr->map_flags & BPF_F_NO_PREALLOC);
|
||||
struct bpf_htab *htab;
|
||||
int err, i;
|
||||
u64 cost;
|
||||
|
||||
htab = kzalloc(sizeof(*htab), GFP_USER);
|
||||
htab = kzalloc(sizeof(*htab), GFP_USER | __GFP_ACCOUNT);
|
||||
if (!htab)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -480,30 +480,18 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
|
||||
htab->n_buckets > U32_MAX / sizeof(struct bucket))
|
||||
goto free_htab;
|
||||
|
||||
cost = (u64) htab->n_buckets * sizeof(struct bucket) +
|
||||
(u64) htab->elem_size * htab->map.max_entries;
|
||||
|
||||
if (percpu)
|
||||
cost += (u64) round_up(htab->map.value_size, 8) *
|
||||
num_possible_cpus() * htab->map.max_entries;
|
||||
else
|
||||
cost += (u64) htab->elem_size * num_possible_cpus();
|
||||
|
||||
/* if map size is larger than memlock limit, reject it */
|
||||
err = bpf_map_charge_init(&htab->map.memory, cost);
|
||||
if (err)
|
||||
goto free_htab;
|
||||
|
||||
err = -ENOMEM;
|
||||
htab->buckets = bpf_map_area_alloc(htab->n_buckets *
|
||||
sizeof(struct bucket),
|
||||
htab->map.numa_node);
|
||||
if (!htab->buckets)
|
||||
goto free_charge;
|
||||
goto free_htab;
|
||||
|
||||
for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++) {
|
||||
htab->map_locked[i] = __alloc_percpu_gfp(sizeof(int),
|
||||
sizeof(int), GFP_USER);
|
||||
htab->map_locked[i] = bpf_map_alloc_percpu(&htab->map,
|
||||
sizeof(int),
|
||||
sizeof(int),
|
||||
GFP_USER);
|
||||
if (!htab->map_locked[i])
|
||||
goto free_map_locked;
|
||||
}
|
||||
@@ -538,8 +526,6 @@ free_map_locked:
|
||||
for (i = 0; i < HASHTAB_MAP_LOCK_COUNT; i++)
|
||||
free_percpu(htab->map_locked[i]);
|
||||
bpf_map_area_free(htab->buckets);
|
||||
free_charge:
|
||||
bpf_map_charge_finish(&htab->map.memory);
|
||||
free_htab:
|
||||
lockdep_unregister_key(&htab->lockdep_key);
|
||||
kfree(htab);
|
||||
@@ -925,8 +911,9 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
|
||||
l_new = ERR_PTR(-E2BIG);
|
||||
goto dec_count;
|
||||
}
|
||||
l_new = kmalloc_node(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN,
|
||||
htab->map.numa_node);
|
||||
l_new = bpf_map_kmalloc_node(&htab->map, htab->elem_size,
|
||||
GFP_ATOMIC | __GFP_NOWARN,
|
||||
htab->map.numa_node);
|
||||
if (!l_new) {
|
||||
l_new = ERR_PTR(-ENOMEM);
|
||||
goto dec_count;
|
||||
@@ -942,8 +929,8 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
|
||||
pptr = htab_elem_get_ptr(l_new, key_size);
|
||||
} else {
|
||||
/* alloc_percpu zero-fills */
|
||||
pptr = __alloc_percpu_gfp(size, 8,
|
||||
GFP_ATOMIC | __GFP_NOWARN);
|
||||
pptr = bpf_map_alloc_percpu(&htab->map, size, 8,
|
||||
GFP_ATOMIC | __GFP_NOWARN);
|
||||
if (!pptr) {
|
||||
kfree(l_new);
|
||||
l_new = ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -164,10 +164,10 @@ static int cgroup_storage_update_elem(struct bpf_map *map, void *key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
new = kmalloc_node(sizeof(struct bpf_storage_buffer) +
|
||||
map->value_size,
|
||||
__GFP_ZERO | GFP_ATOMIC | __GFP_NOWARN,
|
||||
map->numa_node);
|
||||
new = bpf_map_kmalloc_node(map, sizeof(struct bpf_storage_buffer) +
|
||||
map->value_size,
|
||||
__GFP_ZERO | GFP_ATOMIC | __GFP_NOWARN,
|
||||
map->numa_node);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -287,8 +287,6 @@ static struct bpf_map *cgroup_storage_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
int numa_node = bpf_map_attr_numa_node(attr);
|
||||
struct bpf_cgroup_storage_map *map;
|
||||
struct bpf_map_memory mem;
|
||||
int ret;
|
||||
|
||||
if (attr->key_size != sizeof(struct bpf_cgroup_storage_key) &&
|
||||
attr->key_size != sizeof(__u64))
|
||||
@@ -308,18 +306,10 @@ static struct bpf_map *cgroup_storage_map_alloc(union bpf_attr *attr)
|
||||
/* max_entries is not used and enforced to be 0 */
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ret = bpf_map_charge_init(&mem, sizeof(struct bpf_cgroup_storage_map));
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
map = kmalloc_node(sizeof(struct bpf_cgroup_storage_map),
|
||||
__GFP_ZERO | GFP_USER, numa_node);
|
||||
if (!map) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
__GFP_ZERO | GFP_USER | __GFP_ACCOUNT, numa_node);
|
||||
if (!map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
bpf_map_charge_move(&map->map.memory, &mem);
|
||||
|
||||
/* copy mandatory map attributes */
|
||||
bpf_map_init_from_attr(&map->map, attr);
|
||||
@@ -496,9 +486,9 @@ static size_t bpf_cgroup_storage_calculate_size(struct bpf_map *map, u32 *pages)
|
||||
struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
|
||||
enum bpf_cgroup_storage_type stype)
|
||||
{
|
||||
const gfp_t gfp = __GFP_ZERO | GFP_USER;
|
||||
struct bpf_cgroup_storage *storage;
|
||||
struct bpf_map *map;
|
||||
gfp_t flags;
|
||||
size_t size;
|
||||
u32 pages;
|
||||
|
||||
@@ -508,23 +498,19 @@ struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
|
||||
|
||||
size = bpf_cgroup_storage_calculate_size(map, &pages);
|
||||
|
||||
if (bpf_map_charge_memlock(map, pages))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
storage = kmalloc_node(sizeof(struct bpf_cgroup_storage),
|
||||
__GFP_ZERO | GFP_USER, map->numa_node);
|
||||
storage = bpf_map_kmalloc_node(map, sizeof(struct bpf_cgroup_storage),
|
||||
gfp, map->numa_node);
|
||||
if (!storage)
|
||||
goto enomem;
|
||||
|
||||
flags = __GFP_ZERO | GFP_USER;
|
||||
|
||||
if (stype == BPF_CGROUP_STORAGE_SHARED) {
|
||||
storage->buf = kmalloc_node(size, flags, map->numa_node);
|
||||
storage->buf = bpf_map_kmalloc_node(map, size, gfp,
|
||||
map->numa_node);
|
||||
if (!storage->buf)
|
||||
goto enomem;
|
||||
check_and_init_map_lock(map, storage->buf->data);
|
||||
} else {
|
||||
storage->percpu_buf = __alloc_percpu_gfp(size, 8, flags);
|
||||
storage->percpu_buf = bpf_map_alloc_percpu(map, size, 8, gfp);
|
||||
if (!storage->percpu_buf)
|
||||
goto enomem;
|
||||
}
|
||||
@@ -534,7 +520,6 @@ struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(struct bpf_prog *prog,
|
||||
return storage;
|
||||
|
||||
enomem:
|
||||
bpf_map_uncharge_memlock(map, pages);
|
||||
kfree(storage);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@@ -561,16 +546,11 @@ void bpf_cgroup_storage_free(struct bpf_cgroup_storage *storage)
|
||||
{
|
||||
enum bpf_cgroup_storage_type stype;
|
||||
struct bpf_map *map;
|
||||
u32 pages;
|
||||
|
||||
if (!storage)
|
||||
return;
|
||||
|
||||
map = &storage->map->map;
|
||||
|
||||
bpf_cgroup_storage_calculate_size(map, &pages);
|
||||
bpf_map_uncharge_memlock(map, pages);
|
||||
|
||||
stype = cgroup_storage_type(map);
|
||||
if (stype == BPF_CGROUP_STORAGE_SHARED)
|
||||
call_rcu(&storage->rcu, free_shared_cgroup_storage_rcu);
|
||||
|
||||
@@ -282,8 +282,8 @@ static struct lpm_trie_node *lpm_trie_node_alloc(const struct lpm_trie *trie,
|
||||
if (value)
|
||||
size += trie->map.value_size;
|
||||
|
||||
node = kmalloc_node(size, GFP_ATOMIC | __GFP_NOWARN,
|
||||
trie->map.numa_node);
|
||||
node = bpf_map_kmalloc_node(&trie->map, size, GFP_ATOMIC | __GFP_NOWARN,
|
||||
trie->map.numa_node);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
@@ -540,8 +540,6 @@ out:
|
||||
static struct bpf_map *trie_alloc(union bpf_attr *attr)
|
||||
{
|
||||
struct lpm_trie *trie;
|
||||
u64 cost = sizeof(*trie), cost_per_node;
|
||||
int ret;
|
||||
|
||||
if (!bpf_capable())
|
||||
return ERR_PTR(-EPERM);
|
||||
@@ -557,7 +555,7 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr)
|
||||
attr->value_size > LPM_VAL_SIZE_MAX)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
trie = kzalloc(sizeof(*trie), GFP_USER | __GFP_NOWARN);
|
||||
trie = kzalloc(sizeof(*trie), GFP_USER | __GFP_NOWARN | __GFP_ACCOUNT);
|
||||
if (!trie)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -567,20 +565,9 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr)
|
||||
offsetof(struct bpf_lpm_trie_key, data);
|
||||
trie->max_prefixlen = trie->data_size * 8;
|
||||
|
||||
cost_per_node = sizeof(struct lpm_trie_node) +
|
||||
attr->value_size + trie->data_size;
|
||||
cost += (u64) attr->max_entries * cost_per_node;
|
||||
|
||||
ret = bpf_map_charge_init(&trie->map.memory, cost);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
spin_lock_init(&trie->lock);
|
||||
|
||||
return &trie->map;
|
||||
out_err:
|
||||
kfree(trie);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void trie_free(struct bpf_map *map)
|
||||
|
||||
@@ -66,29 +66,21 @@ static int queue_stack_map_alloc_check(union bpf_attr *attr)
|
||||
|
||||
static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
int ret, numa_node = bpf_map_attr_numa_node(attr);
|
||||
struct bpf_map_memory mem = {0};
|
||||
int numa_node = bpf_map_attr_numa_node(attr);
|
||||
struct bpf_queue_stack *qs;
|
||||
u64 size, queue_size, cost;
|
||||
u64 size, queue_size;
|
||||
|
||||
size = (u64) attr->max_entries + 1;
|
||||
cost = queue_size = sizeof(*qs) + size * attr->value_size;
|
||||
|
||||
ret = bpf_map_charge_init(&mem, cost);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
queue_size = sizeof(*qs) + size * attr->value_size;
|
||||
|
||||
qs = bpf_map_area_alloc(queue_size, numa_node);
|
||||
if (!qs) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
if (!qs)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
memset(qs, 0, sizeof(*qs));
|
||||
|
||||
bpf_map_init_from_attr(&qs->map, attr);
|
||||
|
||||
bpf_map_charge_move(&qs->map.memory, &mem);
|
||||
qs->size = size;
|
||||
|
||||
raw_spin_lock_init(&qs->lock);
|
||||
|
||||
@@ -150,9 +150,8 @@ static void reuseport_array_free(struct bpf_map *map)
|
||||
|
||||
static struct bpf_map *reuseport_array_alloc(union bpf_attr *attr)
|
||||
{
|
||||
int err, numa_node = bpf_map_attr_numa_node(attr);
|
||||
int numa_node = bpf_map_attr_numa_node(attr);
|
||||
struct reuseport_array *array;
|
||||
struct bpf_map_memory mem;
|
||||
u64 array_size;
|
||||
|
||||
if (!bpf_capable())
|
||||
@@ -161,20 +160,13 @@ static struct bpf_map *reuseport_array_alloc(union bpf_attr *attr)
|
||||
array_size = sizeof(*array);
|
||||
array_size += (u64)attr->max_entries * sizeof(struct sock *);
|
||||
|
||||
err = bpf_map_charge_init(&mem, array_size);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* allocate all map elements and zero-initialize them */
|
||||
array = bpf_map_area_alloc(array_size, numa_node);
|
||||
if (!array) {
|
||||
bpf_map_charge_finish(&mem);
|
||||
if (!array)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* copy mandatory map attributes */
|
||||
bpf_map_init_from_attr(&array->map, attr);
|
||||
bpf_map_charge_move(&array->map.memory, &mem);
|
||||
|
||||
return &array->map;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ struct bpf_ringbuf {
|
||||
|
||||
struct bpf_ringbuf_map {
|
||||
struct bpf_map map;
|
||||
struct bpf_map_memory memory;
|
||||
struct bpf_ringbuf *rb;
|
||||
};
|
||||
|
||||
@@ -60,8 +59,8 @@ struct bpf_ringbuf_hdr {
|
||||
|
||||
static struct bpf_ringbuf *bpf_ringbuf_area_alloc(size_t data_sz, int numa_node)
|
||||
{
|
||||
const gfp_t flags = GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN |
|
||||
__GFP_ZERO;
|
||||
const gfp_t flags = GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL |
|
||||
__GFP_NOWARN | __GFP_ZERO;
|
||||
int nr_meta_pages = RINGBUF_PGOFF + RINGBUF_POS_PAGES;
|
||||
int nr_data_pages = data_sz >> PAGE_SHIFT;
|
||||
int nr_pages = nr_meta_pages + nr_data_pages;
|
||||
@@ -88,10 +87,7 @@ static struct bpf_ringbuf *bpf_ringbuf_area_alloc(size_t data_sz, int numa_node)
|
||||
* user-space implementations significantly.
|
||||
*/
|
||||
array_size = (nr_meta_pages + 2 * nr_data_pages) * sizeof(*pages);
|
||||
if (array_size > PAGE_SIZE)
|
||||
pages = vmalloc_node(array_size, numa_node);
|
||||
else
|
||||
pages = kmalloc_node(array_size, flags, numa_node);
|
||||
pages = bpf_map_area_alloc(array_size, numa_node);
|
||||
if (!pages)
|
||||
return NULL;
|
||||
|
||||
@@ -134,7 +130,7 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node)
|
||||
|
||||
rb = bpf_ringbuf_area_alloc(data_sz, numa_node);
|
||||
if (!rb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return NULL;
|
||||
|
||||
spin_lock_init(&rb->spinlock);
|
||||
init_waitqueue_head(&rb->waitq);
|
||||
@@ -150,8 +146,6 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node)
|
||||
static struct bpf_map *ringbuf_map_alloc(union bpf_attr *attr)
|
||||
{
|
||||
struct bpf_ringbuf_map *rb_map;
|
||||
u64 cost;
|
||||
int err;
|
||||
|
||||
if (attr->map_flags & ~RINGBUF_CREATE_FLAG_MASK)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -167,32 +161,19 @@ static struct bpf_map *ringbuf_map_alloc(union bpf_attr *attr)
|
||||
return ERR_PTR(-E2BIG);
|
||||
#endif
|
||||
|
||||
rb_map = kzalloc(sizeof(*rb_map), GFP_USER);
|
||||
rb_map = kzalloc(sizeof(*rb_map), GFP_USER | __GFP_ACCOUNT);
|
||||
if (!rb_map)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
bpf_map_init_from_attr(&rb_map->map, attr);
|
||||
|
||||
cost = sizeof(struct bpf_ringbuf_map) +
|
||||
sizeof(struct bpf_ringbuf) +
|
||||
attr->max_entries;
|
||||
err = bpf_map_charge_init(&rb_map->map.memory, cost);
|
||||
if (err)
|
||||
goto err_free_map;
|
||||
|
||||
rb_map->rb = bpf_ringbuf_alloc(attr->max_entries, rb_map->map.numa_node);
|
||||
if (IS_ERR(rb_map->rb)) {
|
||||
err = PTR_ERR(rb_map->rb);
|
||||
goto err_uncharge;
|
||||
if (!rb_map->rb) {
|
||||
kfree(rb_map);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return &rb_map->map;
|
||||
|
||||
err_uncharge:
|
||||
bpf_map_charge_finish(&rb_map->map.memory);
|
||||
err_free_map:
|
||||
kfree(rb_map);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void bpf_ringbuf_free(struct bpf_ringbuf *rb)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user