diff options
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index a3f726bb42ea..c691b9e972e3 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -94,6 +94,11 @@ static int check_uarg_tail_zero(void __user *uaddr, | |||
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
96 | 96 | ||
97 | const struct bpf_map_ops bpf_map_offload_ops = { | ||
98 | .map_alloc = bpf_map_offload_map_alloc, | ||
99 | .map_free = bpf_map_offload_map_free, | ||
100 | }; | ||
101 | |||
97 | static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) | 102 | static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) |
98 | { | 103 | { |
99 | const struct bpf_map_ops *ops; | 104 | const struct bpf_map_ops *ops; |
@@ -111,6 +116,8 @@ static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) | |||
111 | if (err) | 116 | if (err) |
112 | return ERR_PTR(err); | 117 | return ERR_PTR(err); |
113 | } | 118 | } |
119 | if (attr->map_ifindex) | ||
120 | ops = &bpf_map_offload_ops; | ||
114 | map = ops->map_alloc(attr); | 121 | map = ops->map_alloc(attr); |
115 | if (IS_ERR(map)) | 122 | if (IS_ERR(map)) |
116 | return map; | 123 | return map; |
@@ -208,16 +215,25 @@ static int bpf_map_alloc_id(struct bpf_map *map) | |||
208 | return id > 0 ? 0 : id; | 215 | return id > 0 ? 0 : id; |
209 | } | 216 | } |
210 | 217 | ||
211 | static void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) | 218 | void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock) |
212 | { | 219 | { |
213 | unsigned long flags; | 220 | unsigned long flags; |
214 | 221 | ||
222 | /* Offloaded maps are removed from the IDR store when their device | ||
223 | * disappears - even if someone holds an fd to them they are unusable, | ||
224 | * the memory is gone, all ops will fail; they are simply waiting for | ||
225 | * refcnt to drop to be freed. | ||
226 | */ | ||
227 | if (!map->id) | ||
228 | return; | ||
229 | |||
215 | if (do_idr_lock) | 230 | if (do_idr_lock) |
216 | spin_lock_irqsave(&map_idr_lock, flags); | 231 | spin_lock_irqsave(&map_idr_lock, flags); |
217 | else | 232 | else |
218 | __acquire(&map_idr_lock); | 233 | __acquire(&map_idr_lock); |
219 | 234 | ||
220 | idr_remove(&map_idr, map->id); | 235 | idr_remove(&map_idr, map->id); |
236 | map->id = 0; | ||
221 | 237 | ||
222 | if (do_idr_lock) | 238 | if (do_idr_lock) |
223 | spin_unlock_irqrestore(&map_idr_lock, flags); | 239 | spin_unlock_irqrestore(&map_idr_lock, flags); |
@@ -397,7 +413,7 @@ static int bpf_obj_name_cpy(char *dst, const char *src) | |||
397 | return 0; | 413 | return 0; |
398 | } | 414 | } |
399 | 415 | ||
400 | #define BPF_MAP_CREATE_LAST_FIELD map_name | 416 | #define BPF_MAP_CREATE_LAST_FIELD map_ifindex |
401 | /* called via syscall */ | 417 | /* called via syscall */ |
402 | static int map_create(union bpf_attr *attr) | 418 | static int map_create(union bpf_attr *attr) |
403 | { | 419 | { |
@@ -585,8 +601,10 @@ static int map_lookup_elem(union bpf_attr *attr) | |||
585 | if (!value) | 601 | if (!value) |
586 | goto free_key; | 602 | goto free_key; |
587 | 603 | ||
588 | if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || | 604 | if (bpf_map_is_dev_bound(map)) { |
589 | map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { | 605 | err = bpf_map_offload_lookup_elem(map, key, value); |
606 | } else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH || | ||
607 | map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) { | ||
590 | err = bpf_percpu_hash_copy(map, key, value); | 608 | err = bpf_percpu_hash_copy(map, key, value); |
591 | } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { | 609 | } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) { |
592 | err = bpf_percpu_array_copy(map, key, value); | 610 | err = bpf_percpu_array_copy(map, key, value); |
@@ -673,7 +691,10 @@ static int map_update_elem(union bpf_attr *attr) | |||
673 | goto free_value; | 691 | goto free_value; |
674 | 692 | ||
675 | /* Need to create a kthread, thus must support schedule */ | 693 | /* Need to create a kthread, thus must support schedule */ |
676 | if (map->map_type == BPF_MAP_TYPE_CPUMAP) { | 694 | if (bpf_map_is_dev_bound(map)) { |
695 | err = bpf_map_offload_update_elem(map, key, value, attr->flags); | ||
696 | goto out; | ||
697 | } else if (map->map_type == BPF_MAP_TYPE_CPUMAP) { | ||
677 | err = map->ops->map_update_elem(map, key, value, attr->flags); | 698 | err = map->ops->map_update_elem(map, key, value, attr->flags); |
678 | goto out; | 699 | goto out; |
679 | } | 700 | } |
@@ -750,6 +771,11 @@ static int map_delete_elem(union bpf_attr *attr) | |||
750 | goto err_put; | 771 | goto err_put; |
751 | } | 772 | } |
752 | 773 | ||
774 | if (bpf_map_is_dev_bound(map)) { | ||
775 | err = bpf_map_offload_delete_elem(map, key); | ||
776 | goto out; | ||
777 | } | ||
778 | |||
753 | preempt_disable(); | 779 | preempt_disable(); |
754 | __this_cpu_inc(bpf_prog_active); | 780 | __this_cpu_inc(bpf_prog_active); |
755 | rcu_read_lock(); | 781 | rcu_read_lock(); |
@@ -757,7 +783,7 @@ static int map_delete_elem(union bpf_attr *attr) | |||
757 | rcu_read_unlock(); | 783 | rcu_read_unlock(); |
758 | __this_cpu_dec(bpf_prog_active); | 784 | __this_cpu_dec(bpf_prog_active); |
759 | preempt_enable(); | 785 | preempt_enable(); |
760 | 786 | out: | |
761 | if (!err) | 787 | if (!err) |
762 | trace_bpf_map_delete_elem(map, ufd, key); | 788 | trace_bpf_map_delete_elem(map, ufd, key); |
763 | kfree(key); | 789 | kfree(key); |
@@ -807,9 +833,15 @@ static int map_get_next_key(union bpf_attr *attr) | |||
807 | if (!next_key) | 833 | if (!next_key) |
808 | goto free_key; | 834 | goto free_key; |
809 | 835 | ||
836 | if (bpf_map_is_dev_bound(map)) { | ||
837 | err = bpf_map_offload_get_next_key(map, key, next_key); | ||
838 | goto out; | ||
839 | } | ||
840 | |||
810 | rcu_read_lock(); | 841 | rcu_read_lock(); |
811 | err = map->ops->map_get_next_key(map, key, next_key); | 842 | err = map->ops->map_get_next_key(map, key, next_key); |
812 | rcu_read_unlock(); | 843 | rcu_read_unlock(); |
844 | out: | ||
813 | if (err) | 845 | if (err) |
814 | goto free_next_key; | 846 | goto free_next_key; |
815 | 847 | ||