aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorMauricio Vasquez B <mauricio.vasquez@polito.it>2018-10-18 09:16:30 -0400
committerAlexei Starovoitov <ast@kernel.org>2018-10-19 16:24:31 -0400
commitbd513cd08f10cbe28856f99ae951e86e86803861 (patch)
tree4af4c4453badd34c259ad0c8f3140216c22519e2 /kernel/bpf/syscall.c
parentf1a2e44a3aeccb3ff18d3ccc0b0203e70b95bd92 (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.c66
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
1004static 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
1056free_value:
1057 kfree(value);
1058free_key:
1059 kfree(key);
1060err_put:
1061 fdput(f);
1062 return err;
1063}
1064
1002static const struct bpf_prog_ops * const bpf_prog_types[] = { 1065static 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;