diff options
Diffstat (limited to 'kernel/bpf/hashtab.c')
| -rw-r--r-- | kernel/bpf/hashtab.c | 30 | 
1 files changed, 28 insertions, 2 deletions
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 1815e97d4c9c..1fccba6e88c4 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -821,6 +821,32 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr,  	}  } +static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr, +			    void *value, bool onallcpus) +{ +	/* When using prealloc and not setting the initial value on all cpus, +	 * zero-fill element values for other cpus (just as what happens when +	 * not using prealloc). Otherwise, bpf program has no way to ensure +	 * known initial values for cpus other than current one +	 * (onallcpus=false always when coming from bpf prog). +	 */ +	if (htab_is_prealloc(htab) && !onallcpus) { +		u32 size = round_up(htab->map.value_size, 8); +		int current_cpu = raw_smp_processor_id(); +		int cpu; + +		for_each_possible_cpu(cpu) { +			if (cpu == current_cpu) +				bpf_long_memcpy(per_cpu_ptr(pptr, cpu), value, +						size); +			else +				memset(per_cpu_ptr(pptr, cpu), 0, size); +		} +	} else { +		pcpu_copy_value(htab, pptr, value, onallcpus); +	} +} +  static bool fd_htab_map_needs_adjust(const struct bpf_htab *htab)  {  	return htab->map.map_type == BPF_MAP_TYPE_HASH_OF_MAPS && @@ -891,7 +917,7 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,  			}  		} -		pcpu_copy_value(htab, pptr, value, onallcpus); +		pcpu_init_value(htab, pptr, value, onallcpus);  		if (!prealloc)  			htab_elem_set_ptr(l_new, key_size, pptr); @@ -1183,7 +1209,7 @@ static int __htab_lru_percpu_map_update_elem(struct bpf_map *map, void *key,  		pcpu_copy_value(htab, htab_elem_get_ptr(l_old, key_size),  				value, onallcpus);  	} else { -		pcpu_copy_value(htab, htab_elem_get_ptr(l_new, key_size), +		pcpu_init_value(htab, htab_elem_get_ptr(l_new, key_size),  				value, onallcpus);  		hlist_nulls_add_head_rcu(&l_new->hash_node, head);  		l_new = NULL;  | 
