Home / Alt manpages / proc_kpagecount(5)

  • proc_kpagecount(5)
  • File format
  • linux

Read Physical-Page Mapping Counts from /proc/kpagecount

You will finish with a repeatable way to read the mapping count for a physical page frame, interpret the binary file correctly, and tell a missing file from a permissions problem. Allow about fifteen minutes. You need a Linux shell, the installed core utilities, and elevated privileges for the actual read.

1. Check the local contract

The file is not a text report. /proc/kpagecount contains one 64-bit count for each physical page frame, indexed by page frame number, or PFN. The first 64-bit value belongs to PFN 0, the next to PFN 1, and so on.

This interface has existed since Linux 2.6.25. The local manpage is from Linux man-pages 6.7, dated 15 August 2023. The manpage describes the interface, while the running kernel decides whether it is available and who may read it.

$ man 5 proc_kpagecount
$ uname -sr
Linux 6.8.0-139-generic

Checkpoint: confirm that your system knows the file before writing a script around it:

$ stat /proc/kpagecount
  File: /proc/kpagecount
  ...

The reported size is commonly zero because procfs files are generated interfaces. That does not mean there are no records.

2. Check access without changing anything

Read the permissions and the kernel configuration. Both commands are ordinary, read-only checks:

$ stat -c 'mode=%A owner=%U group=%G' /proc/kpagecount
mode=-r-------- owner=root group=root
$ grep '^CONFIG_PROC_PAGE_MONITOR=' /boot/config-$(uname -r)
CONFIG_PROC_PAGE_MONITOR=y

The exact mode can differ. On this machine the file is root-readable only, so a normal user receives Permission denied. Use sudo for the narrow read, rather than changing procfs permissions or relaxing a system policy. Do not add a broad sudo rule for a script that accepts an arbitrary PFN.

If the configuration file is absent, that is not proof that the option is disabled. Some distributions expose kernel configuration through /proc/config.gz, and some expose neither. The decisive check is whether the procfs file exists.

3. Read one PFN record

Use an explicit PFN placeholder and read exactly one 8-byte record. dd skips records of 8 bytes, then od prints the unsigned value in decimal:

$ PFN='12345'
$ sudo dd if=/proc/kpagecount bs=8 skip="$PFN" count=1 status=none | od -An -tu8
                    2

Here, 2 is an example result, not a guaranteed value. It means the selected physical page frame is currently mapped twice according to this interface. A result of 0 is also valid. It means the counter for that PFN is zero at the instant it was read.

Validate the placeholder before using it in a script. It must be a non-negative integer, and it should refer to a PFN that your system could plausibly expose. A very large value may simply produce an end-of-file error or no useful record:

$ case "$PFN" in
    ''|*[!0-9]*) printf 'PFN must be a non-negative integer\n' >&2; exit 2 ;;
  esac
$ sudo dd if=/proc/kpagecount bs=8 skip="$PFN" count=1 status=none | od -An -tu8
                    2

Do not use a text tool such as grep or awk on this file. Its records are binary 64-bit integers, not newline-delimited text.

4. Obtain a PFN from pagemap when you need a real process page

/proc/kpagecount starts with physical frames, not virtual addresses and not process IDs. To relate a count to a process page, you first need the PFN from that process's /proc/PID/pagemap record. That is a separate binary interface containing one 64-bit value per virtual page.

This boundary matters. A virtual address is not a valid skip value for /proc/kpagecount. Neither is a PID. Use the PFN supplied by a pagemap reader, and account for the system page size when calculating which pagemap record describes a virtual address.

Access to pagemap is separately governed by ptrace permissions, so a process may be able to see one interface but not the other. If you are investigating a process you do not own, stop at the permission check rather than trying to bypass it.

5. Treat the number as a snapshot

The count can change while you are reading or comparing it. A process can map or unmap a page, fork, exit, or change its memory layout between two reads. Take repeated samples only when that is useful, and label them with a time or sequence number:

$ for attempt in 1 2 3; do
    printf 'sample %s: ' "$attempt"
    sudo dd if=/proc/kpagecount bs=8 skip="$PFN" count=1 status=none | od -An -tu8
  done
sample 1:                     2
sample 2:                     2
sample 3:                     3

These values are illustrative. A changing value is not automatically an error. It may be the observation you were looking for.

Keep the read-only investigation separate from any action based on it. Do not unmap memory, kill a process, change a service unit, or alter kernel settings just because a count looks unexpected. Those are different operations with their own evidence and rollback requirements.

6. Diagnose the common failures

  • No such file or directory: the running kernel is not exposing this procfs interface. Check that procfs is mounted and inspect the kernel configuration. The manpage says the interface is present only when CONFIG_PROC_PAGE_MONITOR is enabled.
  • Permission denied: use a narrowly scoped elevated read if you are authorised. Do not make the file world-readable.
  • No numeric output: check the pipeline's exit status and stderr. A failed dd can leave od with no input, which is not a zero count.
  • An implausible result: confirm that the index is a PFN, not a virtual address, PID, byte offset, or pagemap record number. Confirm that the reader is handling 64-bit values.

There is no undo step for the examples in this guide: they only read procfs. Close the shell or remove any temporary local variables if you no longer need them.

Done means

  • You confirmed that /proc/kpagecount exists on the running kernel.
  • You checked its access policy and used sudo only for the read that needed it.
  • You read one 64-bit record using a PFN as the index.
  • You did not mistake a virtual address or PID for a PFN.
  • You treated the result as a changing snapshot, not a permanent property.