diff options
author | Mauricio Vasquez B <mauricio.vasquez@polito.it> | 2018-10-18 09:16:30 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-10-19 16:24:31 -0400 |
commit | bd513cd08f10cbe28856f99ae951e86e86803861 (patch) | |
tree | 4af4c4453badd34c259ad0c8f3140216c22519e2 /kernel/bpf/syscall.c | |
parent | f1a2e44a3aeccb3ff18d3ccc0b0203e70b95bd92 (diff) |
bpf: add MAP_LOOKUP_AND_DELETE_ELEM syscall
The previous patch implemented a bpf queue/stack maps that
provided the peek/pop/push functions. There is not a direct
relationship between those functions and the current maps
syscalls, hence a new MAP_LOOKUP_AND_DELETE_ELEM syscall is added,
this is mapped to the pop operation in the queue/stack maps
and it is still to implement in other kind of maps.
Signed-off-by: Mauricio Vasquez B <mauricio.vasquez@polito.it>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r-- | kernel/bpf/syscall.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 1617407f9ee5..49ae64a26562 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c | |||
@@ -999,6 +999,69 @@ err_put: | |||
999 | return err; | 999 | return err; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value | ||
1003 | |||
1004 | static int map_lookup_and_delete_elem(union bpf_attr *attr) | ||
1005 | { | ||
1006 | void __user *ukey = u64_to_user_ptr(attr->key); | ||
1007 | void __user *uvalue = u64_to_user_ptr(attr->value); | ||
1008 | int ufd = attr->map_fd; | ||
1009 | struct bpf_map *map; | ||
1010 | void *key, *value, *ptr; | ||
1011 | u32 value_size; | ||
1012 | struct fd f; | ||
1013 | int err; | ||
1014 | |||
1015 | if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM)) | ||
1016 | return -EINVAL; | ||
1017 | |||
1018 | f = fdget(ufd); | ||
1019 | map = __bpf_map_get(f); | ||
1020 | if (IS_ERR(map)) | ||
1021 | return PTR_ERR(map); | ||
1022 | |||
1023 | if (!(f.file->f_mode & FMODE_CAN_WRITE)) { | ||
1024 | err = -EPERM; | ||
1025 | goto err_put; | ||
1026 | } | ||
1027 | |||
1028 | key = __bpf_copy_key(ukey, map->key_size); | ||
1029 | if (IS_ERR(key)) { | ||
1030 | err = PTR_ERR(key); | ||
1031 | goto err_put; | ||
1032 | } | ||
1033 | |||
1034 | value_size = map->value_size; | ||
1035 | |||
1036 | err = -ENOMEM; | ||
1037 | value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); | ||
1038 | if (!value) | ||
1039 | goto free_key; | ||
1040 | |||
1041 | if (map->map_type == BPF_MAP_TYPE_QUEUE || | ||
1042 | map->map_type == BPF_MAP_TYPE_STACK) { | ||
1043 | err = map->ops->map_pop_elem(map, value); | ||
1044 | } else { | ||
1045 | err = -ENOTSUPP; | ||
1046 | } | ||
1047 | |||
1048 | if (err) | ||
1049 | goto free_value; | ||
1050 | |||
1051 | if (copy_to_user(uvalue, value, value_size) != 0) | ||
1052 | goto free_value; | ||
1053 | |||
1054 | err = 0; | ||
1055 | |||
1056 | free_value: | ||
1057 | kfree(value); | ||
1058 | free_key: | ||
1059 | kfree(key); | ||
1060 | err_put: | ||
1061 | fdput(f); | ||
1062 | return err; | ||
1063 | } | ||
1064 | |||
1002 | static const struct bpf_prog_ops * const bpf_prog_types[] = { | 1065 | static const struct bpf_prog_ops * const bpf_prog_types[] = { |
1003 | #define BPF_PROG_TYPE(_id, _name) \ | 1066 | #define BPF_PROG_TYPE(_id, _name) \ |
1004 | [_id] = & _name ## _prog_ops, | 1067 | [_id] = & _name ## _prog_ops, |
@@ -2472,6 +2535,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz | |||
2472 | case BPF_TASK_FD_QUERY: | 2535 | case BPF_TASK_FD_QUERY: |
2473 | err = bpf_task_fd_query(&attr, uattr); | 2536 | err = bpf_task_fd_query(&attr, uattr); |
2474 | break; | 2537 | break; |
2538 | case BPF_MAP_LOOKUP_AND_DELETE_ELEM: | ||
2539 | err = map_lookup_and_delete_elem(&attr); | ||
2540 | break; | ||
2475 | default: | 2541 | default: |
2476 | err = -EINVAL; | 2542 | err = -EINVAL; |
2477 | break; | 2543 | break; |