Issue
Is there a way in order to check if the page in question is used by specified process?
i.e. I have a pointer to struct page
and struct task_struct
and I want to obtain a boolean value denoting if the page is in process's VMA. Currently I'm stuck at getting the virtual address of the page in process's VMA. If I get it, I'll be able to traverse down the pgd
and see if it is there.
I've tried the approach been taken in vma_address()
(at mm/rmap.c
) but while looping over task's mm_struct->mmap
the virtual address appears to be different for each vm_area_struct
in the list. This contradicts with the find_vma()
(at 'mm/mmap.c`) which scans the task's VMA (though doing the search of corresponding rb-tree) working with the fixed address that is supplied as an argument.
So, what is the correct way of doing such things?
Solution
It turns out that there's the only way to just scan the whole VMA jumping by PAGE_SIZE
like so:
struct page *page_by_address(const struct mm_struct *const mm,
const unsigned long address)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
struct page *page = NULL;
pgd = pgd_offset(mm, address);
if (!pgd_present(*pgd))
goto do_return;
pud = pud_offset(pgd, address);
if (!pud_present(*pud))
goto do_return;
pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd))
goto do_return;
pte = pte_offset_kernel(pmd, address);
if (!pte_present(*pte))
goto do_return;
page = pte_page(*pte);
do_return:
return page;
}
int contains_page(const struct mm_struct *const mm, struct page *const page)
{
int contains = 0;
if (mm != NULL) {
const struct vm_area_struct *vma = mm->mmap;
while (vma != NULL) {
unsigned long address;
for (address = vma->vm_start; !contains && address < vma->vm_end; address += PAGE_SIZE) {
contains = (page_by_address(mm, address) == page);
}
vma = vma->vm_next;
}
}
return contains;
}
Answered By - Dmitry Volosnykh