diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
| -rw-r--r-- | kernel/bpf/syscall.c | 40 | 
1 files changed, 27 insertions, 13 deletions
| diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 0d3313d02a7e..3b39550d8485 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -82,6 +82,14 @@ static void bpf_map_free_deferred(struct work_struct *work)  	map->ops->map_free(map);  } +static void bpf_map_put_uref(struct bpf_map *map) +{ +	if (atomic_dec_and_test(&map->usercnt)) { +		if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) +			bpf_fd_array_map_clear(map); +	} +} +  /* decrement map refcnt and schedule it for freeing via workqueue   * (unrelying map implementation ops->map_free() might sleep)   */ @@ -93,17 +101,15 @@ void bpf_map_put(struct bpf_map *map)  	}  } -static int bpf_map_release(struct inode *inode, struct file *filp) +void bpf_map_put_with_uref(struct bpf_map *map)  { -	struct bpf_map *map = filp->private_data; - -	if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY) -		/* prog_array stores refcnt-ed bpf_prog pointers -		 * release them all when user space closes prog_array_fd -		 */ -		bpf_fd_array_map_clear(map); - +	bpf_map_put_uref(map);  	bpf_map_put(map); +} + +static int bpf_map_release(struct inode *inode, struct file *filp) +{ +	bpf_map_put_with_uref(filp->private_data);  	return 0;  } @@ -142,6 +148,7 @@ static int map_create(union bpf_attr *attr)  		return PTR_ERR(map);  	atomic_set(&map->refcnt, 1); +	atomic_set(&map->usercnt, 1);  	err = bpf_map_charge_memlock(map);  	if (err) @@ -174,7 +181,14 @@ struct bpf_map *__bpf_map_get(struct fd f)  	return f.file->private_data;  } -struct bpf_map *bpf_map_get(u32 ufd) +void bpf_map_inc(struct bpf_map *map, bool uref) +{ +	atomic_inc(&map->refcnt); +	if (uref) +		atomic_inc(&map->usercnt); +} + +struct bpf_map *bpf_map_get_with_uref(u32 ufd)  {  	struct fd f = fdget(ufd);  	struct bpf_map *map; @@ -183,7 +197,7 @@ struct bpf_map *bpf_map_get(u32 ufd)  	if (IS_ERR(map))  		return map; -	atomic_inc(&map->refcnt); +	bpf_map_inc(map, true);  	fdput(f);  	return map; @@ -226,7 +240,7 @@ static int map_lookup_elem(union bpf_attr *attr)  		goto free_key;  	err = -ENOMEM; -	value = kmalloc(map->value_size, GFP_USER); +	value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);  	if (!value)  		goto free_key; @@ -285,7 +299,7 @@ static int map_update_elem(union bpf_attr *attr)  		goto free_key;  	err = -ENOMEM; -	value = kmalloc(map->value_size, GFP_USER); +	value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);  	if (!value)  		goto free_key; | 
