diff mbox series

[bpf-next,v1,2/8] bpf: Add bpf_page_to_pfn helper

Message ID 20211116054237.100814-3-memxor@gmail.com (mailing list archive)
State New, archived
Headers show
Series Introduce BPF iterators for io_uring and epoll | expand

Commit Message

Kumar Kartikeya Dwivedi Nov. 16, 2021, 5:42 a.m. UTC
In CRIU, we need to be able to determine whether the page pinned by
io_uring is still present in the same range in the process VMA.
/proc/<pid>/pagemap gives us the PFN, hence using this helper we can
establish this mapping easily from the iterator side.

It is a simple wrapper over the in-kernel page_to_pfn helper, and
ensures the passed in pointer is a struct page PTR_TO_BTF_ID. This is
obtained from the bvec of io_uring_ubuf for the CRIU usecase.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 fs/io_uring.c                  | 17 +++++++++++++++++
 include/linux/bpf.h            |  1 +
 include/uapi/linux/bpf.h       |  9 +++++++++
 kernel/trace/bpf_trace.c       |  2 ++
 scripts/bpf_doc.py             |  2 ++
 tools/include/uapi/linux/bpf.h |  9 +++++++++
 6 files changed, 40 insertions(+)

Comments

kernel test robot Nov. 17, 2021, 12:35 p.m. UTC | #1
Hi Kumar,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/0day-ci/linux/commits/Kumar-Kartikeya-Dwivedi/Introduce-BPF-iterators-for-io_uring-and-epoll/20211116-140234
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
config: arm-randconfig-r006-20211116 (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/567c9b678d5ade1a63c993cfa10394902d4671ca
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Kumar-Kartikeya-Dwivedi/Introduce-BPF-iterators-for-io_uring-and-epoll/20211116-140234
        git checkout 567c9b678d5ade1a63c993cfa10394902d4671ca
        # save the attached .config to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   arm-linux-gnueabi-ld: kernel/trace/bpf_trace.o: in function `bpf_tracing_func_proto':
>> bpf_trace.c:(.text+0x1930): undefined reference to `bpf_page_to_pfn_proto'
>> arm-linux-gnueabi-ld: bpf_trace.c:(.text+0x1934): undefined reference to `bpf_page_to_pfn_proto'

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Nov. 17, 2021, 1:39 p.m. UTC | #2
Hi Kumar,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on bpf-next/master]

url:    https://github.com/0day-ci/linux/commits/Kumar-Kartikeya-Dwivedi/Introduce-BPF-iterators-for-io_uring-and-epoll/20211116-140234
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
config: i386-randconfig-a014-20211116 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/567c9b678d5ade1a63c993cfa10394902d4671ca
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Kumar-Kartikeya-Dwivedi/Introduce-BPF-iterators-for-io_uring-and-epoll/20211116-140234
        git checkout 567c9b678d5ade1a63c993cfa10394902d4671ca
        # save the attached .config to linux build tree
        mkdir build_dir
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: kernel/trace/bpf_trace.o: in function `bpf_tracing_func_proto':
>> kernel/trace/bpf_trace.c:1216: undefined reference to `bpf_page_to_pfn_proto'


vim +1216 kernel/trace/bpf_trace.c

  1093	
  1094	static const struct bpf_func_proto *
  1095	bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
  1096	{
  1097		switch (func_id) {
  1098		case BPF_FUNC_map_lookup_elem:
  1099			return &bpf_map_lookup_elem_proto;
  1100		case BPF_FUNC_map_update_elem:
  1101			return &bpf_map_update_elem_proto;
  1102		case BPF_FUNC_map_delete_elem:
  1103			return &bpf_map_delete_elem_proto;
  1104		case BPF_FUNC_map_push_elem:
  1105			return &bpf_map_push_elem_proto;
  1106		case BPF_FUNC_map_pop_elem:
  1107			return &bpf_map_pop_elem_proto;
  1108		case BPF_FUNC_map_peek_elem:
  1109			return &bpf_map_peek_elem_proto;
  1110		case BPF_FUNC_ktime_get_ns:
  1111			return &bpf_ktime_get_ns_proto;
  1112		case BPF_FUNC_ktime_get_boot_ns:
  1113			return &bpf_ktime_get_boot_ns_proto;
  1114		case BPF_FUNC_ktime_get_coarse_ns:
  1115			return &bpf_ktime_get_coarse_ns_proto;
  1116		case BPF_FUNC_tail_call:
  1117			return &bpf_tail_call_proto;
  1118		case BPF_FUNC_get_current_pid_tgid:
  1119			return &bpf_get_current_pid_tgid_proto;
  1120		case BPF_FUNC_get_current_task:
  1121			return &bpf_get_current_task_proto;
  1122		case BPF_FUNC_get_current_task_btf:
  1123			return &bpf_get_current_task_btf_proto;
  1124		case BPF_FUNC_task_pt_regs:
  1125			return &bpf_task_pt_regs_proto;
  1126		case BPF_FUNC_get_current_uid_gid:
  1127			return &bpf_get_current_uid_gid_proto;
  1128		case BPF_FUNC_get_current_comm:
  1129			return &bpf_get_current_comm_proto;
  1130		case BPF_FUNC_trace_printk:
  1131			return bpf_get_trace_printk_proto();
  1132		case BPF_FUNC_get_smp_processor_id:
  1133			return &bpf_get_smp_processor_id_proto;
  1134		case BPF_FUNC_get_numa_node_id:
  1135			return &bpf_get_numa_node_id_proto;
  1136		case BPF_FUNC_perf_event_read:
  1137			return &bpf_perf_event_read_proto;
  1138		case BPF_FUNC_current_task_under_cgroup:
  1139			return &bpf_current_task_under_cgroup_proto;
  1140		case BPF_FUNC_get_prandom_u32:
  1141			return &bpf_get_prandom_u32_proto;
  1142		case BPF_FUNC_probe_write_user:
  1143			return security_locked_down(LOCKDOWN_BPF_WRITE_USER) < 0 ?
  1144			       NULL : bpf_get_probe_write_proto();
  1145		case BPF_FUNC_probe_read_user:
  1146			return &bpf_probe_read_user_proto;
  1147		case BPF_FUNC_probe_read_kernel:
  1148			return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
  1149			       NULL : &bpf_probe_read_kernel_proto;
  1150		case BPF_FUNC_probe_read_user_str:
  1151			return &bpf_probe_read_user_str_proto;
  1152		case BPF_FUNC_probe_read_kernel_str:
  1153			return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
  1154			       NULL : &bpf_probe_read_kernel_str_proto;
  1155	#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
  1156		case BPF_FUNC_probe_read:
  1157			return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
  1158			       NULL : &bpf_probe_read_compat_proto;
  1159		case BPF_FUNC_probe_read_str:
  1160			return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
  1161			       NULL : &bpf_probe_read_compat_str_proto;
  1162	#endif
  1163	#ifdef CONFIG_CGROUPS
  1164		case BPF_FUNC_get_current_cgroup_id:
  1165			return &bpf_get_current_cgroup_id_proto;
  1166		case BPF_FUNC_get_current_ancestor_cgroup_id:
  1167			return &bpf_get_current_ancestor_cgroup_id_proto;
  1168	#endif
  1169		case BPF_FUNC_send_signal:
  1170			return &bpf_send_signal_proto;
  1171		case BPF_FUNC_send_signal_thread:
  1172			return &bpf_send_signal_thread_proto;
  1173		case BPF_FUNC_perf_event_read_value:
  1174			return &bpf_perf_event_read_value_proto;
  1175		case BPF_FUNC_get_ns_current_pid_tgid:
  1176			return &bpf_get_ns_current_pid_tgid_proto;
  1177		case BPF_FUNC_ringbuf_output:
  1178			return &bpf_ringbuf_output_proto;
  1179		case BPF_FUNC_ringbuf_reserve:
  1180			return &bpf_ringbuf_reserve_proto;
  1181		case BPF_FUNC_ringbuf_submit:
  1182			return &bpf_ringbuf_submit_proto;
  1183		case BPF_FUNC_ringbuf_discard:
  1184			return &bpf_ringbuf_discard_proto;
  1185		case BPF_FUNC_ringbuf_query:
  1186			return &bpf_ringbuf_query_proto;
  1187		case BPF_FUNC_jiffies64:
  1188			return &bpf_jiffies64_proto;
  1189		case BPF_FUNC_get_task_stack:
  1190			return &bpf_get_task_stack_proto;
  1191		case BPF_FUNC_copy_from_user:
  1192			return prog->aux->sleepable ? &bpf_copy_from_user_proto : NULL;
  1193		case BPF_FUNC_snprintf_btf:
  1194			return &bpf_snprintf_btf_proto;
  1195		case BPF_FUNC_per_cpu_ptr:
  1196			return &bpf_per_cpu_ptr_proto;
  1197		case BPF_FUNC_this_cpu_ptr:
  1198			return &bpf_this_cpu_ptr_proto;
  1199		case BPF_FUNC_task_storage_get:
  1200			return &bpf_task_storage_get_proto;
  1201		case BPF_FUNC_task_storage_delete:
  1202			return &bpf_task_storage_delete_proto;
  1203		case BPF_FUNC_for_each_map_elem:
  1204			return &bpf_for_each_map_elem_proto;
  1205		case BPF_FUNC_snprintf:
  1206			return &bpf_snprintf_proto;
  1207		case BPF_FUNC_get_func_ip:
  1208			return &bpf_get_func_ip_proto_tracing;
  1209		case BPF_FUNC_get_branch_snapshot:
  1210			return &bpf_get_branch_snapshot_proto;
  1211		case BPF_FUNC_find_vma:
  1212			return &bpf_find_vma_proto;
  1213		case BPF_FUNC_trace_vprintk:
  1214			return bpf_get_trace_vprintk_proto();
  1215		case BPF_FUNC_page_to_pfn:
> 1216			return &bpf_page_to_pfn_proto;
  1217		default:
  1218			return bpf_base_func_proto(func_id);
  1219		}
  1220	}
  1221	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Yonghong Song Nov. 18, 2021, 5:27 p.m. UTC | #3
On 11/15/21 9:42 PM, Kumar Kartikeya Dwivedi wrote:
> In CRIU, we need to be able to determine whether the page pinned by
> io_uring is still present in the same range in the process VMA.
> /proc/<pid>/pagemap gives us the PFN, hence using this helper we can
> establish this mapping easily from the iterator side.
> 
> It is a simple wrapper over the in-kernel page_to_pfn helper, and
> ensures the passed in pointer is a struct page PTR_TO_BTF_ID. This is
> obtained from the bvec of io_uring_ubuf for the CRIU usecase.
> 
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
>   fs/io_uring.c                  | 17 +++++++++++++++++
>   include/linux/bpf.h            |  1 +
>   include/uapi/linux/bpf.h       |  9 +++++++++
>   kernel/trace/bpf_trace.c       |  2 ++
>   scripts/bpf_doc.py             |  2 ++
>   tools/include/uapi/linux/bpf.h |  9 +++++++++
>   6 files changed, 40 insertions(+)
> 
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index 46a110989155..9e9df6767e29 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -11295,6 +11295,23 @@ static struct bpf_iter_reg io_uring_buf_reg_info = {
>   	.seq_info	   = &bpf_io_uring_buf_seq_info,
>   };
>   
> +BPF_CALL_1(bpf_page_to_pfn, struct page *, page)
> +{
> +	/* PTR_TO_BTF_ID can be NULL */
> +	if (!page)
> +		return U64_MAX;
> +	return page_to_pfn(page);
> +}
> +
> +BTF_ID_LIST_SINGLE(btf_page_to_pfn_ids, struct, page)
> +
> +const struct bpf_func_proto bpf_page_to_pfn_proto = {
> +	.func		= bpf_page_to_pfn,
> +	.ret_type	= RET_INTEGER,
> +	.arg1_type	= ARG_PTR_TO_BTF_ID,
> +	.arg1_btf_id	= &btf_page_to_pfn_ids[0],

Does this helper need to be gpl_only?

> +};
> +
>   static int __init io_uring_iter_init(void)
>   {
>   	io_uring_buf_reg_info.ctx_arg_info[0].btf_id = btf_io_uring_ids[0];
[...]
Kumar Kartikeya Dwivedi Nov. 18, 2021, 6:30 p.m. UTC | #4
On Thu, Nov 18, 2021 at 10:57:15PM IST, Yonghong Song wrote:
>
>
> On 11/15/21 9:42 PM, Kumar Kartikeya Dwivedi wrote:
> > In CRIU, we need to be able to determine whether the page pinned by
> > io_uring is still present in the same range in the process VMA.
> > /proc/<pid>/pagemap gives us the PFN, hence using this helper we can
> > establish this mapping easily from the iterator side.
> >
> > It is a simple wrapper over the in-kernel page_to_pfn helper, and
> > ensures the passed in pointer is a struct page PTR_TO_BTF_ID. This is
> > obtained from the bvec of io_uring_ubuf for the CRIU usecase.
> >
> > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > ---
> >   fs/io_uring.c                  | 17 +++++++++++++++++
> >   include/linux/bpf.h            |  1 +
> >   include/uapi/linux/bpf.h       |  9 +++++++++
> >   kernel/trace/bpf_trace.c       |  2 ++
> >   scripts/bpf_doc.py             |  2 ++
> >   tools/include/uapi/linux/bpf.h |  9 +++++++++
> >   6 files changed, 40 insertions(+)
> >
> > diff --git a/fs/io_uring.c b/fs/io_uring.c
> > index 46a110989155..9e9df6767e29 100644
> > --- a/fs/io_uring.c
> > +++ b/fs/io_uring.c
> > @@ -11295,6 +11295,23 @@ static struct bpf_iter_reg io_uring_buf_reg_info = {
> >   	.seq_info	   = &bpf_io_uring_buf_seq_info,
> >   };
> > +BPF_CALL_1(bpf_page_to_pfn, struct page *, page)
> > +{
> > +	/* PTR_TO_BTF_ID can be NULL */
> > +	if (!page)
> > +		return U64_MAX;
> > +	return page_to_pfn(page);
> > +}
> > +
> > +BTF_ID_LIST_SINGLE(btf_page_to_pfn_ids, struct, page)
> > +
> > +const struct bpf_func_proto bpf_page_to_pfn_proto = {
> > +	.func		= bpf_page_to_pfn,
> > +	.ret_type	= RET_INTEGER,
> > +	.arg1_type	= ARG_PTR_TO_BTF_ID,
> > +	.arg1_btf_id	= &btf_page_to_pfn_ids[0],
>
> Does this helper need to be gpl_only?
>

Not sure about it, it wraps over a macro.

> > +};
> > +
> >   static int __init io_uring_iter_init(void)
> >   {
> >   	io_uring_buf_reg_info.ctx_arg_info[0].btf_id = btf_io_uring_ids[0];
> [...]

--
Kartikeya
Yonghong Song Nov. 18, 2021, 7:18 p.m. UTC | #5
On 11/18/21 10:30 AM, Kumar Kartikeya Dwivedi wrote:
> On Thu, Nov 18, 2021 at 10:57:15PM IST, Yonghong Song wrote:
>>
>>
>> On 11/15/21 9:42 PM, Kumar Kartikeya Dwivedi wrote:
>>> In CRIU, we need to be able to determine whether the page pinned by
>>> io_uring is still present in the same range in the process VMA.
>>> /proc/<pid>/pagemap gives us the PFN, hence using this helper we can
>>> establish this mapping easily from the iterator side.
>>>
>>> It is a simple wrapper over the in-kernel page_to_pfn helper, and
>>> ensures the passed in pointer is a struct page PTR_TO_BTF_ID. This is
>>> obtained from the bvec of io_uring_ubuf for the CRIU usecase.
>>>
>>> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
>>> ---
>>>    fs/io_uring.c                  | 17 +++++++++++++++++
>>>    include/linux/bpf.h            |  1 +
>>>    include/uapi/linux/bpf.h       |  9 +++++++++
>>>    kernel/trace/bpf_trace.c       |  2 ++
>>>    scripts/bpf_doc.py             |  2 ++
>>>    tools/include/uapi/linux/bpf.h |  9 +++++++++
>>>    6 files changed, 40 insertions(+)
>>>
>>> diff --git a/fs/io_uring.c b/fs/io_uring.c
>>> index 46a110989155..9e9df6767e29 100644
>>> --- a/fs/io_uring.c
>>> +++ b/fs/io_uring.c
>>> @@ -11295,6 +11295,23 @@ static struct bpf_iter_reg io_uring_buf_reg_info = {
>>>    	.seq_info	   = &bpf_io_uring_buf_seq_info,
>>>    };
>>> +BPF_CALL_1(bpf_page_to_pfn, struct page *, page)
>>> +{
>>> +	/* PTR_TO_BTF_ID can be NULL */
>>> +	if (!page)
>>> +		return U64_MAX;
>>> +	return page_to_pfn(page);
>>> +}
>>> +
>>> +BTF_ID_LIST_SINGLE(btf_page_to_pfn_ids, struct, page)
>>> +
>>> +const struct bpf_func_proto bpf_page_to_pfn_proto = {
>>> +	.func		= bpf_page_to_pfn,
>>> +	.ret_type	= RET_INTEGER,
>>> +	.arg1_type	= ARG_PTR_TO_BTF_ID,
>>> +	.arg1_btf_id	= &btf_page_to_pfn_ids[0],
>>
>> Does this helper need to be gpl_only?

The typically guideline whether the same info can be retrieved from
userspace. If yes, no gpl is needed. Otherwe, it needs to be gpl.

Also, the helper is implemented in io_uring.c and the helper
is used by tracing programs. Maybe we can put the helper
in bpf_trace.c? The helper itself is not tied to io_uring, right?

>>
> 
> Not sure about it, it wraps over a macro.
> 
>>> +};
>>> +
>>>    static int __init io_uring_iter_init(void)
>>>    {
>>>    	io_uring_buf_reg_info.ctx_arg_info[0].btf_id = btf_io_uring_ids[0];
>> [...]
> 
> --
> Kartikeya
>
Kumar Kartikeya Dwivedi Nov. 18, 2021, 7:22 p.m. UTC | #6
On Fri, Nov 19, 2021 at 12:48:39AM IST, Yonghong Song wrote:
>
>
> On 11/18/21 10:30 AM, Kumar Kartikeya Dwivedi wrote:
> > On Thu, Nov 18, 2021 at 10:57:15PM IST, Yonghong Song wrote:
> > >
> > >
> > > On 11/15/21 9:42 PM, Kumar Kartikeya Dwivedi wrote:
> > > > In CRIU, we need to be able to determine whether the page pinned by
> > > > io_uring is still present in the same range in the process VMA.
> > > > /proc/<pid>/pagemap gives us the PFN, hence using this helper we can
> > > > establish this mapping easily from the iterator side.
> > > >
> > > > It is a simple wrapper over the in-kernel page_to_pfn helper, and
> > > > ensures the passed in pointer is a struct page PTR_TO_BTF_ID. This is
> > > > obtained from the bvec of io_uring_ubuf for the CRIU usecase.
> > > >
> > > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > > > ---
> > > >    fs/io_uring.c                  | 17 +++++++++++++++++
> > > >    include/linux/bpf.h            |  1 +
> > > >    include/uapi/linux/bpf.h       |  9 +++++++++
> > > >    kernel/trace/bpf_trace.c       |  2 ++
> > > >    scripts/bpf_doc.py             |  2 ++
> > > >    tools/include/uapi/linux/bpf.h |  9 +++++++++
> > > >    6 files changed, 40 insertions(+)
> > > >
> > > > diff --git a/fs/io_uring.c b/fs/io_uring.c
> > > > index 46a110989155..9e9df6767e29 100644
> > > > --- a/fs/io_uring.c
> > > > +++ b/fs/io_uring.c
> > > > @@ -11295,6 +11295,23 @@ static struct bpf_iter_reg io_uring_buf_reg_info = {
> > > >    	.seq_info	   = &bpf_io_uring_buf_seq_info,
> > > >    };
> > > > +BPF_CALL_1(bpf_page_to_pfn, struct page *, page)
> > > > +{
> > > > +	/* PTR_TO_BTF_ID can be NULL */
> > > > +	if (!page)
> > > > +		return U64_MAX;
> > > > +	return page_to_pfn(page);
> > > > +}
> > > > +
> > > > +BTF_ID_LIST_SINGLE(btf_page_to_pfn_ids, struct, page)
> > > > +
> > > > +const struct bpf_func_proto bpf_page_to_pfn_proto = {
> > > > +	.func		= bpf_page_to_pfn,
> > > > +	.ret_type	= RET_INTEGER,
> > > > +	.arg1_type	= ARG_PTR_TO_BTF_ID,
> > > > +	.arg1_btf_id	= &btf_page_to_pfn_ids[0],
> > >
> > > Does this helper need to be gpl_only?
>
> The typically guideline whether the same info can be retrieved from
> userspace. If yes, no gpl is needed. Otherwe, it needs to be gpl.
>

I think it can already be obtained using /proc/<PID>/pagemap, so not needed.

> Also, the helper is implemented in io_uring.c and the helper
> is used by tracing programs. Maybe we can put the helper
> in bpf_trace.c? The helper itself is not tied to io_uring, right?
>

Right, I'll move it outside CONFIG_IO_URING in v2. That's also why the build
failed on this patch.

--
Kartikeya
diff mbox series

Patch

diff --git a/fs/io_uring.c b/fs/io_uring.c
index 46a110989155..9e9df6767e29 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -11295,6 +11295,23 @@  static struct bpf_iter_reg io_uring_buf_reg_info = {
 	.seq_info	   = &bpf_io_uring_buf_seq_info,
 };
 
+BPF_CALL_1(bpf_page_to_pfn, struct page *, page)
+{
+	/* PTR_TO_BTF_ID can be NULL */
+	if (!page)
+		return U64_MAX;
+	return page_to_pfn(page);
+}
+
+BTF_ID_LIST_SINGLE(btf_page_to_pfn_ids, struct, page)
+
+const struct bpf_func_proto bpf_page_to_pfn_proto = {
+	.func		= bpf_page_to_pfn,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_PTR_TO_BTF_ID,
+	.arg1_btf_id	= &btf_page_to_pfn_ids[0],
+};
+
 static int __init io_uring_iter_init(void)
 {
 	io_uring_buf_reg_info.ctx_arg_info[0].btf_id = btf_io_uring_ids[0];
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index ddb9d4520a3f..fe7b499da781 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2166,6 +2166,7 @@  extern const struct bpf_func_proto bpf_sk_setsockopt_proto;
 extern const struct bpf_func_proto bpf_sk_getsockopt_proto;
 extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto;
 extern const struct bpf_func_proto bpf_find_vma_proto;
+extern const struct bpf_func_proto bpf_page_to_pfn_proto;
 
 const struct bpf_func_proto *tracing_prog_func_proto(
   enum bpf_func_id func_id, const struct bpf_prog *prog);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 3323defa99a1..b70e9da3d722 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -4960,6 +4960,14 @@  union bpf_attr {
  *		**-ENOENT** if *task->mm* is NULL, or no vma contains *addr*.
  *		**-EBUSY** if failed to try lock mmap_lock.
  *		**-EINVAL** for invalid **flags**.
+ *
+ * long bpf_page_to_pfn(struct page *page)
+ *	Description
+ *		Obtain the page frame number (PFN) for the given *struct page*
+ *		pointer.
+ *	Return
+ *		Page Frame Number corresponding to the page pointed to by the
+ *		*struct page* pointer, or U64_MAX if pointer is NULL.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -5143,6 +5151,7 @@  union bpf_attr {
 	FN(skc_to_unix_sock),		\
 	FN(kallsyms_lookup_name),	\
 	FN(find_vma),			\
+	FN(page_to_pfn),		\
 	/* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 25ea521fb8f1..f68a8433be1a 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -1212,6 +1212,8 @@  bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 		return &bpf_find_vma_proto;
 	case BPF_FUNC_trace_vprintk:
 		return bpf_get_trace_vprintk_proto();
+	case BPF_FUNC_page_to_pfn:
+		return &bpf_page_to_pfn_proto;
 	default:
 		return bpf_base_func_proto(func_id);
 	}
diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
index a6403ddf5de7..ae68ca794980 100755
--- a/scripts/bpf_doc.py
+++ b/scripts/bpf_doc.py
@@ -549,6 +549,7 @@  class PrinterHelpers(Printer):
             'struct socket',
             'struct file',
             'struct bpf_timer',
+            'struct page',
     ]
     known_types = {
             '...',
@@ -598,6 +599,7 @@  class PrinterHelpers(Printer):
             'struct socket',
             'struct file',
             'struct bpf_timer',
+            'struct page',
     }
     mapped_types = {
             'u8': '__u8',
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 3323defa99a1..b70e9da3d722 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -4960,6 +4960,14 @@  union bpf_attr {
  *		**-ENOENT** if *task->mm* is NULL, or no vma contains *addr*.
  *		**-EBUSY** if failed to try lock mmap_lock.
  *		**-EINVAL** for invalid **flags**.
+ *
+ * long bpf_page_to_pfn(struct page *page)
+ *	Description
+ *		Obtain the page frame number (PFN) for the given *struct page*
+ *		pointer.
+ *	Return
+ *		Page Frame Number corresponding to the page pointed to by the
+ *		*struct page* pointer, or U64_MAX if pointer is NULL.
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -5143,6 +5151,7 @@  union bpf_attr {
 	FN(skc_to_unix_sock),		\
 	FN(kallsyms_lookup_name),	\
 	FN(find_vma),			\
+	FN(page_to_pfn),		\
 	/* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper