This patch adds BPF_OBJ_GET_INFO_BY_FD support to BTF fd. The original BTF data, which was used to create the BTF fd during the earlier BPF_BTF_LOAD call, will be returned. The userspace is expected to allocate buffer to info.info and the buffer size is set to info.info_len before calling BPF_OBJ_GET_INFO_BY_FD. The original BTF data is copied to the userspace buffer (info.info). Only upto the user's specified info.info_len will be copied. The original BTF data size is set to info.info_len. The userspace needs to check if it is bigger than its allocated buffer size. If it is, the userspace should realloc with the kernel-returned info.info_len and call the BPF_OBJ_GET_INFO_BY_FD again.
Unified · Split
| @@ -10,9 +10,14 @@ struct btf; · 9 unmodified lines | |||
| 10 | struct btf_type; | 10 | struct btf_type; |
| 11 | union bpf_attr; | 11 | union bpf_attr; |
| 12 | 12 | ||
| 13 | extern const struct file_operations btf_fops; | ||
| 14 | |||
| 13 | void btf_put(struct btf *btf); | 15 | void btf_put(struct btf *btf); |
| 14 | int btf_new_fd(const union bpf_attr *attr); | 16 | int btf_new_fd(const union bpf_attr *attr); |
| 15 | struct btf *btf_get_by_fd(int fd); | 17 | struct btf *btf_get_by_fd(int fd); |
| 18 | int btf_get_info_by_fd(const struct btf *btf, | ||
| 19 | const union bpf_attr *attr, | ||
| 20 | union bpf_attr __user *uattr); | ||
| 16 | /* Figure out the size of a type_id. If type_id is a modifier | 21 | /* Figure out the size of a type_id. If type_id is a modifier |
| 17 | * (e.g. const), it will be resolved to find out the type with size. | 22 | * (e.g. const), it will be resolved to find out the type with size. |
| 18 | * | 23 | * |
| @@ -2002,7 +2002,7 @@ static int btf_release(struct inode *inode, struct file *filp) · 2001 unmodified lines | |||
| 2002 | return 0; | 2002 | return 0; |
| 2003 | } | 2003 | } |
| 2004 | 2004 | ||
| 2005 | static const struct file_operations btf_fops = { | 2005 | const struct file_operations btf_fops = { |
| 2006 | .release = btf_release, | 2006 | .release = btf_release, |
| 2007 | }; | 2007 | }; |
| 2008 | 2008 | ||
| @@ -2047,3 +2047,18 @@ struct btf *btf_get_by_fd(int fd) · 38 unmodified lines | |||
| 2047 | 2047 | ||
| 2048 | return btf; | 2048 | return btf; |
| 2049 | } | 2049 | } |
| 2050 | |||
| 2051 | int btf_get_info_by_fd(const struct btf *btf, | ||
| 2052 | const union bpf_attr *attr, | ||
| 2053 | union bpf_attr __user *uattr) | ||
| 2054 | { | ||
| 2055 | void __user *udata = u64_to_user_ptr(attr->info.info); | ||
| 2056 | u32 copy_len = min_t(u32, btf->data_size, | ||
| 2057 | attr->info.info_len); | ||
| 2058 | |||
| 2059 | if (copy_to_user(udata, btf->data, copy_len) || | ||
| 2060 | put_user(btf->data_size, &uattr->info.info_len)) | ||
| 2061 | return -EFAULT; | ||
| 2062 | |||
| 2063 | return 0; | ||
| 2064 | } | ||
| @@ -2017,6 +2017,8 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, · 2016 unmodified lines | |||
| 2017 | else if (f.file->f_op == &bpf_map_fops) | 2017 | else if (f.file->f_op == &bpf_map_fops) |
| 2018 | err = bpf_map_get_info_by_fd(f.file->private_data, attr, | 2018 | err = bpf_map_get_info_by_fd(f.file->private_data, attr, |
| 2019 | uattr); | 2019 | uattr); |
| 2020 | else if (f.file->f_op == &btf_fops) | ||
| 2021 | err = btf_get_info_by_fd(f.file->private_data, attr, uattr); | ||
| 2020 | else | 2022 | else |
| 2021 | err = -EINVAL; | 2023 | err = -EINVAL; |
| 2022 | 2024 | ||