]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - kernel/bpf/syscall.c
Merge tag 'mm-stable-2023-02-20-13-37' of git://git.kernel.org/pub/scm/linux/kernel...
[thirdparty/linux.git] / kernel / bpf / syscall.c
index 9f56b442daa95ff8cb01d6394739afd4e6f2e060..adc83cb82f379df0c9692b5fdd24cbb33319b444 100644 (file)
@@ -181,7 +181,7 @@ static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,
        int err;
 
        /* Need to create a kthread, thus must support schedule */
-       if (bpf_map_is_dev_bound(map)) {
+       if (bpf_map_is_offloaded(map)) {
                return bpf_map_offload_update_elem(map, key, value, flags);
        } else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
                   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
@@ -238,7 +238,7 @@ static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
        void *ptr;
        int err;
 
-       if (bpf_map_is_dev_bound(map))
+       if (bpf_map_is_offloaded(map))
                return bpf_map_offload_lookup_elem(map, key, value);
 
        bpf_disable_instrumentation();
@@ -309,7 +309,7 @@ static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
         * __GFP_RETRY_MAYFAIL to avoid such situations.
         */
 
-       const gfp_t gfp = __GFP_NOWARN | __GFP_ZERO | __GFP_ACCOUNT;
+       gfp_t gfp = bpf_memcg_flags(__GFP_NOWARN | __GFP_ZERO);
        unsigned int flags = 0;
        unsigned long align = 1;
        void *area;
@@ -390,7 +390,7 @@ static int bpf_map_alloc_id(struct bpf_map *map)
        return id > 0 ? 0 : id;
 }
 
-void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
+void bpf_map_free_id(struct bpf_map *map)
 {
        unsigned long flags;
 
@@ -402,18 +402,12 @@ void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock)
        if (!map->id)
                return;
 
-       if (do_idr_lock)
-               spin_lock_irqsave(&map_idr_lock, flags);
-       else
-               __acquire(&map_idr_lock);
+       spin_lock_irqsave(&map_idr_lock, flags);
 
        idr_remove(&map_idr, map->id);
        map->id = 0;
 
-       if (do_idr_lock)
-               spin_unlock_irqrestore(&map_idr_lock, flags);
-       else
-               __release(&map_idr_lock);
+       spin_unlock_irqrestore(&map_idr_lock, flags);
 }
 
 #ifdef CONFIG_MEMCG_KMEM
@@ -424,7 +418,8 @@ static void bpf_map_save_memcg(struct bpf_map *map)
         * So we have to check map->objcg for being NULL each time it's
         * being used.
         */
-       map->objcg = get_obj_cgroup_from_current();
+       if (memcg_bpf_enabled())
+               map->objcg = get_obj_cgroup_from_current();
 }
 
 static void bpf_map_release_memcg(struct bpf_map *map)
@@ -470,6 +465,21 @@ void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
        return ptr;
 }
 
+void *bpf_map_kvcalloc(struct bpf_map *map, size_t n, size_t size,
+                      gfp_t flags)
+{
+       struct mem_cgroup *memcg, *old_memcg;
+       void *ptr;
+
+       memcg = bpf_map_get_memcg(map);
+       old_memcg = set_active_memcg(memcg);
+       ptr = kvcalloc(n, size, flags | __GFP_ACCOUNT);
+       set_active_memcg(old_memcg);
+       mem_cgroup_put(memcg);
+
+       return ptr;
+}
+
 void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
                                    size_t align, gfp_t flags)
 {
@@ -527,9 +537,6 @@ void btf_record_free(struct btf_record *rec)
                return;
        for (i = 0; i < rec->cnt; i++) {
                switch (rec->fields[i].type) {
-               case BPF_SPIN_LOCK:
-               case BPF_TIMER:
-                       break;
                case BPF_KPTR_UNREF:
                case BPF_KPTR_REF:
                        if (rec->fields[i].kptr.module)
@@ -538,7 +545,11 @@ void btf_record_free(struct btf_record *rec)
                        break;
                case BPF_LIST_HEAD:
                case BPF_LIST_NODE:
-                       /* Nothing to release for bpf_list_head */
+               case BPF_RB_ROOT:
+               case BPF_RB_NODE:
+               case BPF_SPIN_LOCK:
+               case BPF_TIMER:
+                       /* Nothing to release */
                        break;
                default:
                        WARN_ON_ONCE(1);
@@ -571,9 +582,6 @@ struct btf_record *btf_record_dup(const struct btf_record *rec)
        new_rec->cnt = 0;
        for (i = 0; i < rec->cnt; i++) {
                switch (fields[i].type) {
-               case BPF_SPIN_LOCK:
-               case BPF_TIMER:
-                       break;
                case BPF_KPTR_UNREF:
                case BPF_KPTR_REF:
                        btf_get(fields[i].kptr.btf);
@@ -584,7 +592,11 @@ struct btf_record *btf_record_dup(const struct btf_record *rec)
                        break;
                case BPF_LIST_HEAD:
                case BPF_LIST_NODE:
-                       /* Nothing to acquire for bpf_list_head */
+               case BPF_RB_ROOT:
+               case BPF_RB_NODE:
+               case BPF_SPIN_LOCK:
+               case BPF_TIMER:
+                       /* Nothing to acquire */
                        break;
                default:
                        ret = -EFAULT;
@@ -664,7 +676,13 @@ void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
                                continue;
                        bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off);
                        break;
+               case BPF_RB_ROOT:
+                       if (WARN_ON_ONCE(rec->spin_lock_off < 0))
+                               continue;
+                       bpf_rb_root_free(field, field_ptr, obj + rec->spin_lock_off);
+                       break;
                case BPF_LIST_NODE:
+               case BPF_RB_NODE:
                        break;
                default:
                        WARN_ON_ONCE(1);
@@ -706,13 +724,13 @@ static void bpf_map_put_uref(struct bpf_map *map)
 }
 
 /* decrement map refcnt and schedule it for freeing via workqueue
- * (unrelying map implementation ops->map_free() might sleep)
+ * (underlying map implementation ops->map_free() might sleep)
  */
-static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
+void bpf_map_put(struct bpf_map *map)
 {
        if (atomic64_dec_and_test(&map->refcnt)) {
                /* bpf_map_free_id() must be called first */
-               bpf_map_free_id(map, do_idr_lock);
+               bpf_map_free_id(map);
                btf_put(map->btf);
                INIT_WORK(&map->work, bpf_map_free_deferred);
                /* Avoid spawning kworkers, since they all might contend
@@ -721,11 +739,6 @@ static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock)
                queue_work(system_unbound_wq, &map->work);
        }
 }
-
-void bpf_map_put(struct bpf_map *map)
-{
-       __bpf_map_put(map, true);
-}
 EXPORT_SYMBOL_GPL(bpf_map_put);
 
 void bpf_map_put_with_uref(struct bpf_map *map)
@@ -1005,7 +1018,8 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,
                return -EINVAL;
 
        map->record = btf_parse_fields(btf, value_type,
-                                      BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD,
+                                      BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD |
+                                      BPF_RB_ROOT,
                                       map->value_size);
        if (!IS_ERR_OR_NULL(map->record)) {
                int i;
@@ -1053,6 +1067,7 @@ static int map_check_btf(struct bpf_map *map, const struct btf *btf,
                                }
                                break;
                        case BPF_LIST_HEAD:
+                       case BPF_RB_ROOT:
                                if (map->map_type != BPF_MAP_TYPE_HASH &&
                                    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
                                    map->map_type != BPF_MAP_TYPE_ARRAY) {
@@ -1483,7 +1498,7 @@ static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
                goto err_put;
        }
 
-       if (bpf_map_is_dev_bound(map)) {
+       if (bpf_map_is_offloaded(map)) {
                err = bpf_map_offload_delete_elem(map, key);
                goto out;
        } else if (IS_FD_PROG_ARRAY(map) ||
@@ -1547,7 +1562,7 @@ static int map_get_next_key(union bpf_attr *attr)
        if (!next_key)
                goto free_key;
 
-       if (bpf_map_is_dev_bound(map)) {
+       if (bpf_map_is_offloaded(map)) {
                err = bpf_map_offload_get_next_key(map, key, next_key);
                goto out;
        }
@@ -1605,7 +1620,7 @@ int generic_map_delete_batch(struct bpf_map *map,
                                   map->key_size))
                        break;
 
-               if (bpf_map_is_dev_bound(map)) {
+               if (bpf_map_is_offloaded(map)) {
                        err = bpf_map_offload_delete_elem(map, key);
                        break;
                }
@@ -1851,7 +1866,7 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr)
                   map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
                   map->map_type == BPF_MAP_TYPE_LRU_HASH ||
                   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
-               if (!bpf_map_is_dev_bound(map)) {
+               if (!bpf_map_is_offloaded(map)) {
                        bpf_disable_instrumentation();
                        rcu_read_lock();
                        err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
@@ -1944,7 +1959,7 @@ static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
        if (!ops)
                return -EINVAL;
 
-       if (!bpf_prog_is_dev_bound(prog->aux))
+       if (!bpf_prog_is_offloaded(prog->aux))
                prog->aux->ops = ops;
        else
                prog->aux->ops = &bpf_offload_prog_ops;
@@ -1972,7 +1987,7 @@ static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
                return;
        if (audit_enabled == AUDIT_OFF)
                return;
-       if (op == BPF_AUDIT_LOAD)
+       if (!in_irq() && !irqs_disabled())
                ctx = audit_context();
        ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
        if (unlikely(!ab))
@@ -2001,7 +2016,7 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
        return id > 0 ? 0 : id;
 }
 
-void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
+void bpf_prog_free_id(struct bpf_prog *prog)
 {
        unsigned long flags;
 
@@ -2013,18 +2028,10 @@ void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
        if (!prog->aux->id)
                return;
 
-       if (do_idr_lock)
-               spin_lock_irqsave(&prog_idr_lock, flags);
-       else
-               __acquire(&prog_idr_lock);
-
+       spin_lock_irqsave(&prog_idr_lock, flags);
        idr_remove(&prog_idr, prog->aux->id);
        prog->aux->id = 0;
-
-       if (do_idr_lock)
-               spin_unlock_irqrestore(&prog_idr_lock, flags);
-       else
-               __release(&prog_idr_lock);
+       spin_unlock_irqrestore(&prog_idr_lock, flags);
 }
 
 static void __bpf_prog_put_rcu(struct rcu_head *rcu)
@@ -2067,17 +2074,15 @@ static void bpf_prog_put_deferred(struct work_struct *work)
        prog = aux->prog;
        perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
        bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
+       bpf_prog_free_id(prog);
        __bpf_prog_put_noref(prog, true);
 }
 
-static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
+static void __bpf_prog_put(struct bpf_prog *prog)
 {
        struct bpf_prog_aux *aux = prog->aux;
 
        if (atomic64_dec_and_test(&aux->refcnt)) {
-               /* bpf_prog_free_id() must be called first */
-               bpf_prog_free_id(prog, do_idr_lock);
-
                if (in_irq() || irqs_disabled()) {
                        INIT_WORK(&aux->work, bpf_prog_put_deferred);
                        schedule_work(&aux->work);
@@ -2089,7 +2094,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock)
 
 void bpf_prog_put(struct bpf_prog *prog)
 {
-       __bpf_prog_put(prog, true);
+       __bpf_prog_put(prog);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_put);
 
@@ -2255,7 +2260,7 @@ bool bpf_prog_get_ok(struct bpf_prog *prog,
 
        if (prog->type != *attach_type)
                return false;
-       if (bpf_prog_is_dev_bound(prog->aux) && !attach_drv)
+       if (bpf_prog_is_offloaded(prog->aux) && !attach_drv)
                return false;
 
        return true;
@@ -2491,7 +2496,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
                                 BPF_F_TEST_STATE_FREQ |
                                 BPF_F_SLEEPABLE |
                                 BPF_F_TEST_RND_HI32 |
-                                BPF_F_XDP_HAS_FRAGS))
+                                BPF_F_XDP_HAS_FRAGS |
+                                BPF_F_XDP_DEV_BOUND_ONLY))
                return -EINVAL;
 
        if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
@@ -2575,7 +2581,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
        prog->aux->attach_btf = attach_btf;
        prog->aux->attach_btf_id = attr->attach_btf_id;
        prog->aux->dst_prog = dst_prog;
-       prog->aux->offload_requested = !!attr->prog_ifindex;
+       prog->aux->dev_bound = !!attr->prog_ifindex;
        prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
        prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
 
@@ -2599,7 +2605,14 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
        prog->gpl_compatible = is_gpl ? 1 : 0;
 
        if (bpf_prog_is_dev_bound(prog->aux)) {
-               err = bpf_prog_offload_init(prog, attr);
+               err = bpf_prog_dev_bound_init(prog, attr);
+               if (err)
+                       goto free_prog_sec;
+       }
+
+       if (type == BPF_PROG_TYPE_EXT && dst_prog &&
+           bpf_prog_is_dev_bound(dst_prog->aux)) {
+               err = bpf_prog_dev_bound_inherit(prog, dst_prog);
                if (err)
                        goto free_prog_sec;
        }
@@ -3997,7 +4010,7 @@ static int bpf_prog_get_info_by_fd(struct file *file,
                        return -EFAULT;
        }
 
-       if (bpf_prog_is_dev_bound(prog->aux)) {
+       if (bpf_prog_is_offloaded(prog->aux)) {
                err = bpf_prog_offload_info_fill(&info, prog);
                if (err)
                        return err;
@@ -4225,7 +4238,7 @@ static int bpf_map_get_info_by_fd(struct file *file,
        }
        info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
 
-       if (bpf_map_is_dev_bound(map)) {
+       if (bpf_map_is_offloaded(map)) {
                err = bpf_map_offload_info_fill(&info, map);
                if (err)
                        return err;
@@ -5319,7 +5332,6 @@ static struct ctl_table bpf_syscall_table[] = {
        {
                .procname       = "bpf_stats_enabled",
                .data           = &bpf_stats_enabled_key.key,
-               .maxlen         = sizeof(bpf_stats_enabled_key),
                .mode           = 0644,
                .proc_handler   = bpf_stats_handler,
        },