summaryrefslogtreecommitdiffstats
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2019-01-31 18:40:09 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2019-02-01 14:55:39 -0500
commit96049f3afd50fe8db69fa0068cdca822e747b1e4 (patch)
treeb082ac077ea0bb78a073a25e540be72034ce0451 /kernel/bpf/syscall.c
parentab963beb9f5db303b4fd7e34e422b96270e5b972 (diff)
bpf: introduce BPF_F_LOCK flag
Introduce BPF_F_LOCK flag for map_lookup and map_update syscall commands and for map_update() helper function. In all these cases take a lock of existing element (which was provided in BTF description) before copying (in or out) the rest of map value. Implementation details that are part of uapi: Array: The array map takes the element lock for lookup/update. Hash: hash map also takes the lock for lookup/update and tries to avoid the bucket lock. If old element exists it takes the element lock and updates the element in place. If element doesn't exist it allocates new one and inserts into hash table while holding the bucket lock. In rare case the hashmap has to take both the bucket lock and the element lock to update old value in place. Cgroup local storage: It is similar to array. update in place and lookup are done with lock taken. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index b29e6dc44650..0834958f1dc4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -682,7 +682,7 @@ static void *__bpf_copy_key(void __user *ukey, u64 key_size)
682} 682}
683 683
684/* last field in 'union bpf_attr' used by this command */ 684/* last field in 'union bpf_attr' used by this command */
685#define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value 685#define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
686 686
687static int map_lookup_elem(union bpf_attr *attr) 687static int map_lookup_elem(union bpf_attr *attr)
688{ 688{
@@ -698,6 +698,9 @@ static int map_lookup_elem(union bpf_attr *attr)
698 if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) 698 if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
699 return -EINVAL; 699 return -EINVAL;
700 700
701 if (attr->flags & ~BPF_F_LOCK)
702 return -EINVAL;
703
701 f = fdget(ufd); 704 f = fdget(ufd);
702 map = __bpf_map_get(f); 705 map = __bpf_map_get(f);
703 if (IS_ERR(map)) 706 if (IS_ERR(map))
@@ -708,6 +711,12 @@ static int map_lookup_elem(union bpf_attr *attr)
708 goto err_put; 711 goto err_put;
709 } 712 }
710 713
714 if ((attr->flags & BPF_F_LOCK) &&
715 !map_value_has_spin_lock(map)) {
716 err = -EINVAL;
717 goto err_put;
718 }
719
711 key = __bpf_copy_key(ukey, map->key_size); 720 key = __bpf_copy_key(ukey, map->key_size);
712 if (IS_ERR(key)) { 721 if (IS_ERR(key)) {
713 err = PTR_ERR(key); 722 err = PTR_ERR(key);
@@ -758,7 +767,13 @@ static int map_lookup_elem(union bpf_attr *attr)
758 err = -ENOENT; 767 err = -ENOENT;
759 } else { 768 } else {
760 err = 0; 769 err = 0;
761 copy_map_value(map, value, ptr); 770 if (attr->flags & BPF_F_LOCK)
771 /* lock 'ptr' and copy everything but lock */
772 copy_map_value_locked(map, value, ptr, true);
773 else
774 copy_map_value(map, value, ptr);
775 /* mask lock, since value wasn't zero inited */
776 check_and_init_map_lock(map, value);
762 } 777 }
763 rcu_read_unlock(); 778 rcu_read_unlock();
764 } 779 }
@@ -818,6 +833,12 @@ static int map_update_elem(union bpf_attr *attr)
818 goto err_put; 833 goto err_put;
819 } 834 }
820 835
836 if ((attr->flags & BPF_F_LOCK) &&
837 !map_value_has_spin_lock(map)) {
838 err = -EINVAL;
839 goto err_put;
840 }
841
821 key = __bpf_copy_key(ukey, map->key_size); 842 key = __bpf_copy_key(ukey, map->key_size);
822 if (IS_ERR(key)) { 843 if (IS_ERR(key)) {
823 err = PTR_ERR(key); 844 err = PTR_ERR(key);