Search code examples
linux-kernelarmvirtual-memorypage-tables

ARM Linux: PTE not writable but dirty


I am aware that ARM architecture emulates the Linux's young and dirty flags by setting them in page fault handlers as discussed here. But recently for a small binary, I observed that a Linux PTE in one of the anonymous segments was set to be not writable and dirty. The following Linux PTE state was observed:

- L_PTE_PRESENT : 1
- L_PTE_YOUNG   : 1 
- L_PTE_DIRTY   : 1
- L_PTE_RDONLY  : 1
- L_PTE_XN      : 0

I couldn't find an explanation for this combination of PTE flags. Does the kernel set this combination for special anonymous VMA segments? What does this combination signify? Any pointers will be helpful. Thanks in advance.


Solution

  • I observed that a Linux PTE in one of the anonymous segments was set to be not writable and dirty... What does this combination signify?

    TL;DR - This simply means that the page is not in a backing store and it is read-only.


    Dirty just means not written to a backing store (swap, mmap file or inode). Many things such as code are always read from a file, so they are backed by an inode.

    If you mmap some read-only memory, then you could get this combination, for example. Other possibilities are a stack guard, allocator run-time buffer overflow detection, and copy-on-write functionality.

    These are not normal. For a typical allocation, you will have something backed by swap and only a write will cause the page to become dirty. So the case is probably less frequent but valid.

    See: ARM Linux PTE bits
            ARM Linux emulate dirty/accessed

    There seems to be little documentation on what the young bit means. young is information about what to swap. If something is young and not accessed for a prolonged time, it is a good candidate to evict. In contrast, dirty is for whether it needs to be swapped. If a page is dirty, then it has not been written to a backing store (a swap file or mmap file, etc). The pager must write out this page then. If it was not dirty (or clean), then the pager can simply discard the memory and re-use.

    The difference between young and dirty is like should and must.

    - L_PTE_PRESENT : 1   - it has physical RAM (not swapped)
    - L_PTE_YOUNG   : 1   - is has not been used
    - L_PTE_DIRTY   : 1   - it is different than backing store
    - L_PTE_RDONLY  : 1   - user space can not write.
    - L_PTE_XN      : 0   - code can execute.
    

    Not present and dirty seem like an impossible condition for instance, but dirty and read-only is valid.