1460 lines · 38.9 KB · C
RawDownload
	else		bpf_map_area_free(array);} static void array_map_seq_show_elem(struct bpf_map *map, void *key,				    struct seq_file *m){	void *value; 	rcu_read_lock(); 	value = array_map_lookup_elem(map, key);	if (!value) {		rcu_read_unlock();		return;	} 	if (map->btf_key_type_id)		seq_printf(m, "%u: ", *(u32 *)key);	btf_type_seq_show(map->btf, map->btf_value_type_id, value, m);	seq_putc(m, '\n'); 	rcu_read_unlock();} static void percpu_array_map_seq_show_elem(struct bpf_map *map, void *key,					   struct seq_file *m){	struct bpf_array *array = container_of(map, struct bpf_array, map);	u32 index = *(u32 *)key;	void __percpu *pptr;	int cpu; 	rcu_read_lock(); 	seq_printf(m, "%u: {\n", *(u32 *)key);	pptr = array->pptrs[index & array->index_mask];	for_each_possible_cpu(cpu) {		seq_printf(m, "\tcpu%d: ", cpu);		btf_type_seq_show(map->btf, map->btf_value_type_id,				  per_cpu_ptr(pptr, cpu), m);		seq_putc(m, '\n');	}	seq_puts(m, "}\n"); 	rcu_read_unlock();} static int array_map_check_btf(struct bpf_map *map,			       const struct btf *btf,			       const struct btf_type *key_type,			       const struct btf_type *value_type){	/* One exception for keyless BTF: .bss/.data/.rodata map */	if (btf_type_is_void(key_type)) {		if (map->map_type != BPF_MAP_TYPE_ARRAY ||		    map->max_entries != 1)			return -EINVAL; 		if (BTF_INFO_KIND(value_type->info) != BTF_KIND_DATASEC)			return -EINVAL; 		return 0;	} 	/*	 * Bpf array can only take a u32 key. This check makes sure	 * that the btf matches the attr used during map_create.	 */	if (!btf_type_is_i32(key_type))		return -EINVAL; 	return 0;} static int array_map_mmap(struct bpf_map *map, struct vm_area_struct *vma){	struct bpf_array *array = container_of(map, struct bpf_array, map);	pgoff_t pgoff = PAGE_ALIGN(sizeof(*array)) >> PAGE_SHIFT; 	if (!(map->map_flags & BPF_F_MMAPABLE))		return -EINVAL; 	if (vma->vm_pgoff * PAGE_SIZE + (vma->vm_end - vma->vm_start) >	    PAGE_ALIGN((u64)array->map.max_entries * array->elem_size))		return -EINVAL; 	return remap_vmalloc_range(vma, array_map_vmalloc_addr(array),				   vma->vm_pgoff + pgoff);} static bool array_map_meta_equal(const struct bpf_map *meta0,				 const struct bpf_map *meta1){	if (!bpf_map_meta_equal(meta0, meta1))		return false;	return meta0->map_flags & BPF_F_INNER_MAP ? true :	       meta0->max_entries == meta1->max_entries;} struct bpf_iter_seq_array_map_info {	struct bpf_map *map;	void *percpu_value_buf;	u32 index;}; static void *bpf_array_map_seq_start(struct seq_file *seq, loff_t *pos){	struct bpf_iter_seq_array_map_info *info = seq->private;	struct bpf_map *map = info->map;	struct bpf_array *array;	u32 index; 	if (info->index >= map->max_entries)		return NULL; 	if (*pos == 0)		++*pos;	array = container_of(map, struct bpf_array, map);	index = info->index & array->index_mask;	if (info->percpu_value_buf)		return (void *)(uintptr_t)array->pptrs[index];	return array_map_elem_ptr(array, index);} static void *bpf_array_map_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct bpf_iter_seq_array_map_info *info = seq->private;	struct bpf_map *map = info->map;	struct bpf_array *array;	u32 index; 	++*pos;	++info->index;	if (info->index >= map->max_entries)		return NULL; 	array = container_of(map, struct bpf_array, map);	index = info->index & array->index_mask;	if (info->percpu_value_buf)		return (void *)(uintptr_t)array->pptrs[index];	return array_map_elem_ptr(array, index);} static int __bpf_array_map_seq_show(struct seq_file *seq, void *v){	struct bpf_iter_seq_array_map_info *info = seq->private;	struct bpf_iter__bpf_map_elem ctx = {};	struct bpf_map *map = info->map;	struct bpf_array *array = container_of(map, struct bpf_array, map);	struct bpf_iter_meta meta;	struct bpf_prog *prog;	int off = 0, cpu = 0;	void __percpu *pptr;	u32 size; 	meta.seq = seq;	prog = bpf_iter_get_info(&meta, v == NULL);	if (!prog)		return 0; 	ctx.meta = &meta;	ctx.map = info->map;	if (v) {		ctx.key = &info->index; 		if (!info->percpu_value_buf) {			ctx.value = v;		} else {			pptr = (void __percpu *)(uintptr_t)v;			size = array->elem_size;			for_each_possible_cpu(cpu) {				copy_map_value_long(map, info->percpu_value_buf + off,						    per_cpu_ptr(pptr, cpu));				check_and_init_map_value(map, info->percpu_value_buf + off);				off += size;			}			ctx.value = info->percpu_value_buf;		}	} 	return bpf_iter_run_prog(prog, &ctx);} static int bpf_array_map_seq_show(struct seq_file *seq, void *v){	return __bpf_array_map_seq_show(seq, v);} static void bpf_array_map_seq_stop(struct seq_file *seq, void *v){	if (!v)		(void)__bpf_array_map_seq_show(seq, NULL);} static int bpf_iter_init_array_map(void *priv_data,				   struct bpf_iter_aux_info *aux){	struct bpf_iter_seq_array_map_info *seq_info = priv_data;	struct bpf_map *map = aux->map;	struct bpf_array *array = container_of(map, struct bpf_array, map);	void *value_buf;	u32 buf_size; 	if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {		buf_size = array->elem_size * num_possible_cpus();		value_buf = kmalloc(buf_size, GFP_USER | __GFP_NOWARN);		if (!value_buf)			return -ENOMEM; 		seq_info->percpu_value_buf = value_buf;	} 	/* bpf_iter_attach_map() acquires a map uref, and the uref may be	 * released before or in the middle of iterating map elements, so	 * acquire an extra map uref for iterator.	 */	bpf_map_inc_with_uref(map);	seq_info->map = map;	return 0;} static void bpf_iter_fini_array_map(void *priv_data){	struct bpf_iter_seq_array_map_info *seq_info = priv_data; 	bpf_map_put_with_uref(seq_info->map);	kfree(seq_info->percpu_value_buf);} static const struct seq_operations bpf_array_map_seq_ops = {	.start	= bpf_array_map_seq_start,	.next	= bpf_array_map_seq_next,	.stop	= bpf_array_map_seq_stop,	.show	= bpf_array_map_seq_show,}; static const struct bpf_iter_seq_info iter_seq_info = {	.seq_ops		= &bpf_array_map_seq_ops,	.init_seq_private	= bpf_iter_init_array_map,	.fini_seq_private	= bpf_iter_fini_array_map,	.seq_priv_size		= sizeof(struct bpf_iter_seq_array_map_info),}; static long bpf_for_each_array_elem(struct bpf_map *map, bpf_callback_t callback_fn,				    void *callback_ctx, u64 flags){	u32 i, key, num_elems = 0;	struct bpf_array *array;	bool is_percpu;	u64 ret = 0;	void *val; 	cant_migrate(); 	if (flags != 0)		return -EINVAL; 	is_percpu = map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;	array = container_of(map, struct bpf_array, map);	for (i = 0; i < map->max_entries; i++) {		if (is_percpu)			val = this_cpu_ptr(array->pptrs[i]);		else			val = array_map_elem_ptr(array, i);		num_elems++;		key = i;		ret = callback_fn((u64)(long)map, (u64)(long)&key,				  (u64)(long)val, (u64)(long)callback_ctx, 0);		/* return value: 0 - continue, 1 - stop and return */		if (ret)			break;	} 	return num_elems;} static u64 array_map_mem_usage(const struct bpf_map *map){	struct bpf_array *array = container_of(map, struct bpf_array, map);	bool percpu = map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;	u32 elem_size = array->elem_size;	u64 entries = map->max_entries;	u64 usage = sizeof(*array); 	if (percpu) {		usage += entries * sizeof(void *);		usage += entries * elem_size * num_possible_cpus();	} else {		if (map->map_flags & BPF_F_MMAPABLE) {			usage = PAGE_ALIGN(usage);			usage += PAGE_ALIGN(entries * elem_size);		} else {			usage += entries * elem_size;		}	}	return usage;} BTF_ID_LIST_SINGLE(array_map_btf_ids, struct, bpf_array)const struct bpf_map_ops array_map_ops = {	.map_meta_equal = array_map_meta_equal,	.map_alloc_check = array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = array_map_free,	.map_get_next_key = bpf_array_get_next_key,	.map_release_uref = array_map_free_internal_structs,	.map_lookup_elem = array_map_lookup_elem,	.map_update_elem = array_map_update_elem,	.map_delete_elem = array_map_delete_elem,	.map_gen_lookup = array_map_gen_lookup,	.map_direct_value_addr = array_map_direct_value_addr,	.map_direct_value_meta = array_map_direct_value_meta,	.map_mmap = array_map_mmap,	.map_seq_show_elem = array_map_seq_show_elem,	.map_check_btf = array_map_check_btf,	.map_lookup_batch = generic_map_lookup_batch,	.map_update_batch = generic_map_update_batch,	.map_set_for_each_callback_args = map_set_for_each_callback_args,	.map_for_each_callback = bpf_for_each_array_elem,	.map_mem_usage = array_map_mem_usage,	.map_btf_id = &array_map_btf_ids[0],	.iter_seq_info = &iter_seq_info,	.map_get_hash = &array_map_get_hash,}; const struct bpf_map_ops percpu_array_map_ops = {	.map_meta_equal = array_map_meta_equal,	.map_alloc_check = array_map_alloc_check,	.map_alloc = array_map_alloc,	.map_free = array_map_free,	.map_get_next_key = bpf_array_get_next_key,	.map_lookup_elem = percpu_array_map_lookup_elem,	.map_gen_lookup = percpu_array_map_gen_lookup,	.map_update_elem = array_map_update_elem,	.map_delete_elem = array_map_delete_elem,	.map_lookup_percpu_elem = percpu_array_map_lookup_percpu_elem,	.map_seq_show_elem = percpu_array_map_seq_show_elem,	.map_check_btf = array_map_check_btf,	.map_lookup_batch = generic_map_lookup_batch,	.map_update_batch = generic_map_update_batch,	.map_set_for_each_callback_args = map_set_for_each_callback_args,	.map_for_each_callback = bpf_for_each_array_elem,	.map_mem_usage = array_map_mem_usage,	.map_btf_id = &array_map_btf_ids[0],	.iter_seq_info = &iter_seq_info,}; static int fd_array_map_alloc_check(union bpf_attr *attr){	/* only file descriptors can be stored in this type of map */	if (attr->value_size != sizeof(u32))		return -EINVAL;	/* Program read-only/write-only not supported for special maps yet. */	if (attr->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG))		return -EINVAL;	return array_map_alloc_check(attr);} static void fd_array_map_free(struct bpf_map *map){	struct bpf_array *array = container_of(map, struct bpf_array, map);	int i; 	/* make sure it's empty */	for (i = 0; i < array->map.max_entries; i++)		BUG_ON(array->ptrs[i] != NULL); 	bpf_map_area_free(array);} static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key){	return ERR_PTR(-EOPNOTSUPP);} /* only called from syscall */int bpf_fd_array_map_lookup_elem(struct bpf_map *map, void *key, u32 *value){	void **elem, *ptr;	int ret =  0; 	if (!map->ops->map_fd_sys_lookup_elem)		return -ENOTSUPP; 	rcu_read_lock();	elem = array_map_lookup_elem(map, key);	if (elem && (ptr = READ_ONCE(*elem)))		*value = map->ops->map_fd_sys_lookup_elem(ptr);	else		ret = -ENOENT;	rcu_read_unlock(); 	return ret;} /* only called from syscall */int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,				 void *key, void *value, u64 map_flags){	struct bpf_array *array = container_of(map, struct bpf_array, map);	void *new_ptr, *old_ptr;	u32 index = *(u32 *)key, ufd; 	if (map_flags != BPF_ANY)		return -EINVAL; 	if (index >= array->map.max_entries)		return -E2BIG; 	ufd = *(u32 *)value;	new_ptr = map->ops->map_fd_get_ptr(map, map_file, ufd);	if (IS_ERR(new_ptr))		return PTR_ERR(new_ptr); 	if (map->ops->map_poke_run) {		mutex_lock(&array->aux->poke_mutex);		old_ptr = xchg(array->ptrs + index, new_ptr);		map->ops->map_poke_run(map, index, old_ptr, new_ptr);		mutex_unlock(&array->aux->poke_mutex);	} else {		old_ptr = xchg(array->ptrs + index, new_ptr);	} 	if (old_ptr)		map->ops->map_fd_put_ptr(map, old_ptr, true);	return 0;} static long __fd_array_map_delete_elem(struct bpf_map *map, void *key, bool need_defer){	struct bpf_array *array = container_of(map, struct bpf_array, map);	void *old_ptr;	u32 index = *(u32 *)key; 	if (index >= array->map.max_entries)		return -E2BIG; 	if (map->ops->map_poke_run) {		mutex_lock(&array->aux->poke_mutex);		old_ptr = xchg(array->ptrs + index, NULL);		map->ops->map_poke_run(map, index, old_ptr, NULL);		mutex_unlock(&array->aux->poke_mutex);	} else {		old_ptr = xchg(array->ptrs + index, NULL);	} 	if (old_ptr) {		map->ops->map_fd_put_ptr(map, old_ptr, need_defer);		return 0;	} else {		return -ENOENT;	}} static long fd_array_map_delete_elem(struct bpf_map *map, void *key){	return __fd_array_map_delete_elem(map, key, true);} static void *prog_fd_array_get_ptr(struct bpf_map *map,				   struct file *map_file, int fd){	struct bpf_prog *prog = bpf_prog_get(fd);	bool is_extended; 	if (IS_ERR(prog))		return prog; 	if (prog->type == BPF_PROG_TYPE_EXT ||	    !bpf_prog_map_compatible(map, prog)) {		bpf_prog_put(prog);		return ERR_PTR(-EINVAL);	} 	mutex_lock(&prog->aux->ext_mutex);	is_extended = prog->aux->is_extended;	if (!is_extended)		prog->aux->prog_array_member_cnt++;	mutex_unlock(&prog->aux->ext_mutex);	if (is_extended) {		/* Extended prog can not be tail callee. It's to prevent a		 * potential infinite loop like:		 * tail callee prog entry -> tail callee prog subprog ->		 * freplace prog entry --tailcall-> tail callee prog entry.		 */		bpf_prog_put(prog);		return ERR_PTR(-EBUSY);	} 	return prog;} static void prog_fd_array_put_ptr(struct bpf_map *map, void *ptr, bool need_defer){	struct bpf_prog *prog = ptr; 	mutex_lock(&prog->aux->ext_mutex);	prog->aux->prog_array_member_cnt--;	mutex_unlock(&prog->aux->ext_mutex);

Lines 501–1000 of 1460. Previous lines