diff options
Diffstat (limited to 'kernel/bpf/arraymap.c')
| -rw-r--r-- | kernel/bpf/arraymap.c | 36 | 
1 files changed, 22 insertions, 14 deletions
| diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index b1f66480135b..027107f4be53 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -26,8 +26,10 @@ static void bpf_array_free_percpu(struct bpf_array *array)  {  	int i; -	for (i = 0; i < array->map.max_entries; i++) +	for (i = 0; i < array->map.max_entries; i++) {  		free_percpu(array->pptrs[i]); +		cond_resched(); +	}  }  static int bpf_array_alloc_percpu(struct bpf_array *array) @@ -43,6 +45,7 @@ static int bpf_array_alloc_percpu(struct bpf_array *array)  			return -ENOMEM;  		}  		array->pptrs[i] = ptr; +		cond_resched();  	}  	return 0; @@ -73,11 +76,11 @@ static 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 numa_node = bpf_map_attr_numa_node(attr); +	int ret, numa_node = bpf_map_attr_numa_node(attr);  	u32 elem_size, index_mask, max_entries;  	bool unpriv = !capable(CAP_SYS_ADMIN); +	u64 cost, array_size, mask64;  	struct bpf_array *array; -	u64 array_size, mask64;  	elem_size = round_up(attr->value_size, 8); @@ -109,8 +112,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  		array_size += (u64) max_entries * elem_size;  	/* make sure there is no u32 overflow later in round_up() */ -	if (array_size >= U32_MAX - PAGE_SIZE) +	cost = array_size; +	if (cost >= U32_MAX - PAGE_SIZE)  		return ERR_PTR(-ENOMEM); +	if (percpu) { +		cost += (u64)attr->max_entries * elem_size * num_possible_cpus(); +		if (cost >= U32_MAX - PAGE_SIZE) +			return ERR_PTR(-ENOMEM); +	} +	cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; + +	ret = bpf_map_precharge_memlock(cost); +	if (ret < 0) +		return ERR_PTR(ret);  	/* allocate all map elements and zero-initialize them */  	array = bpf_map_area_alloc(array_size, numa_node); @@ -121,20 +135,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  	/* copy mandatory map attributes */  	bpf_map_init_from_attr(&array->map, attr); +	array->map.pages = cost;  	array->elem_size = elem_size; -	if (!percpu) -		goto out; - -	array_size += (u64) attr->max_entries * elem_size * num_possible_cpus(); - -	if (array_size >= U32_MAX - PAGE_SIZE || -	    bpf_array_alloc_percpu(array)) { +	if (percpu && bpf_array_alloc_percpu(array)) {  		bpf_map_area_free(array);  		return ERR_PTR(-ENOMEM);  	} -out: -	array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT;  	return &array->map;  } @@ -469,7 +476,7 @@ static u32 prog_fd_array_sys_lookup_elem(void *ptr)  }  /* decrement refcnt of all bpf_progs that are stored in this map */ -void bpf_fd_array_map_clear(struct bpf_map *map) +static void bpf_fd_array_map_clear(struct bpf_map *map)  {  	struct bpf_array *array = container_of(map, struct bpf_array, map);  	int i; @@ -488,6 +495,7 @@ const struct bpf_map_ops prog_array_map_ops = {  	.map_fd_get_ptr = prog_fd_array_get_ptr,  	.map_fd_put_ptr = prog_fd_array_put_ptr,  	.map_fd_sys_lookup_elem = prog_fd_array_sys_lookup_elem, +	.map_release_uref = bpf_fd_array_map_clear,  };  static struct bpf_event_entry *bpf_event_entry_gen(struct file *perf_file, | 
