On Mon, Oct 14, 2024 at 05:49:56PM GMT, Martin KaFai Lau wrote: > From: Martin KaFai Lau <martin.lau@xxxxxxxxxx> > [...] > +static void unpin_uptr_kaddr(void *kaddr) > +{ > + if (kaddr) > + unpin_user_page(virt_to_page(kaddr)); > +} > + > +static void __bpf_obj_unpin_uptrs(struct btf_record *rec, u32 cnt, void *obj) > +{ > + const struct btf_field *field; > + void **uptr_addr; > + int i; > + > + for (i = 0, field = rec->fields; i < cnt; i++, field++) { > + if (field->type != BPF_UPTR) > + continue; > + > + uptr_addr = obj + field->offset; > + unpin_uptr_kaddr(*uptr_addr); > + } > +} > + > +static void bpf_obj_unpin_uptrs(struct btf_record *rec, void *obj) > +{ > + if (!btf_record_has_field(rec, BPF_UPTR)) > + return; > + > + __bpf_obj_unpin_uptrs(rec, rec->cnt, obj); > +} > + > +static int bpf_obj_pin_uptrs(struct btf_record *rec, void *obj) > +{ > + const struct btf_field *field; > + const struct btf_type *t; > + unsigned long start, end; > + struct page *page; > + void **uptr_addr; > + int i, err; > + > + if (!btf_record_has_field(rec, BPF_UPTR)) > + return 0; > + > + for (i = 0, field = rec->fields; i < rec->cnt; i++, field++) { > + if (field->type != BPF_UPTR) > + continue; > + > + uptr_addr = obj + field->offset; > + start = *(unsigned long *)uptr_addr; > + if (!start) > + continue; > + > + t = btf_type_by_id(field->kptr.btf, field->kptr.btf_id); > + if (check_add_overflow(start, t->size, &end)) { > + err = -EFAULT; > + goto unpin_all; > + } > + > + /* The uptr's struct cannot span across two pages */ > + if ((start & PAGE_MASK) != (end & PAGE_MASK)) { > + err = -EOPNOTSUPP; > + goto unpin_all; > + } > + > + err = pin_user_pages_fast(start, 1, FOLL_LONGTERM | FOLL_WRITE, &page); > + if (err != 1) > + goto unpin_all; > + > + *uptr_addr = page_address(page) + offset_in_page(start); Please use kmap(page) instead of page_address(page) and then you will need to kunmap(kptr) on the unpin side.