|
@@ -166,6 +166,7 @@ static void bpf_map_put_uref(struct bpf_map *map)
|
|
|
void bpf_map_put(struct bpf_map *map)
|
|
|
{
|
|
|
if (atomic_dec_and_test(&map->refcnt)) {
|
|
|
+ /* bpf_map_free_id() must be called first */
|
|
|
bpf_map_free_id(map);
|
|
|
INIT_WORK(&map->work, bpf_map_free_deferred);
|
|
|
schedule_work(&map->work);
|
|
@@ -726,6 +727,7 @@ void bpf_prog_put(struct bpf_prog *prog)
|
|
|
{
|
|
|
if (atomic_dec_and_test(&prog->aux->refcnt)) {
|
|
|
trace_bpf_prog_put_rcu(prog);
|
|
|
+ /* bpf_prog_free_id() must be called first */
|
|
|
bpf_prog_free_id(prog);
|
|
|
bpf_prog_kallsyms_del(prog);
|
|
|
call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
|
|
@@ -1069,6 +1071,34 @@ static int bpf_prog_test_run(const union bpf_attr *attr,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+#define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
|
|
|
+
|
|
|
+static int bpf_obj_get_next_id(const union bpf_attr *attr,
|
|
|
+ union bpf_attr __user *uattr,
|
|
|
+ struct idr *idr,
|
|
|
+ spinlock_t *lock)
|
|
|
+{
|
|
|
+ u32 next_id = attr->start_id;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ next_id++;
|
|
|
+ spin_lock_bh(lock);
|
|
|
+ if (!idr_get_next(idr, &next_id))
|
|
|
+ err = -ENOENT;
|
|
|
+ spin_unlock_bh(lock);
|
|
|
+
|
|
|
+ if (!err)
|
|
|
+ err = put_user(next_id, &uattr->next_id);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
|
|
|
{
|
|
|
union bpf_attr attr = {};
|
|
@@ -1146,6 +1176,14 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
|
|
|
case BPF_PROG_TEST_RUN:
|
|
|
err = bpf_prog_test_run(&attr, uattr);
|
|
|
break;
|
|
|
+ case BPF_PROG_GET_NEXT_ID:
|
|
|
+ err = bpf_obj_get_next_id(&attr, uattr,
|
|
|
+ &prog_idr, &prog_idr_lock);
|
|
|
+ break;
|
|
|
+ case BPF_MAP_GET_NEXT_ID:
|
|
|
+ err = bpf_obj_get_next_id(&attr, uattr,
|
|
|
+ &map_idr, &map_idr_lock);
|
|
|
+ break;
|
|
|
default:
|
|
|
err = -EINVAL;
|
|
|
break;
|