Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x86_64: mm: support numa migration pte entry #379

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

hao-lee
Copy link

@hao-lee hao-lee commented Dec 6, 2023

The PRESENT bit alone does not indicate whether a page actually exists. The PRESENT bit is also cleared for numa migration pte entries, even though the page is present. Therefore, to determine if a page truly exists, we need to check pte and convert it to phys in the same way the kernel does.

Fix #370

Signed-off-by: Hao Li [email protected]

The PRESENT bit alone does not indicate whether a page actually exists. The
PRESENT bit is also cleared for numa migration pte entries, even though the
page is present. Therefore, to determine if a page truly exists, we need to
check pte and convert it to phys in the same way the kernel does.

Signed-off-by: Hao Li <[email protected]>
Copy link
Owner

@osandov osandov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a great find, thank you! I left a few comments.

table = entry & ADDRESS_MASK;
if (!(entry & PRESENT) || (entry & PSE) || level == 0) {
table = entry & PTE_PFN_MASK;
if (!(entry & _PAGE_PRESENT) || (entry & PSE) || level == 0) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can huge pages also have numa migration entries? pmd_present() in the kernel checks _PAGE_PROTNONE, so maybe 2MB huge pages can? If so, this check probably needs to be slightly different (and depend on the level).

Comment on lines +663 to +664
if (pte_present(entry))
*phys_addr_ret = pte_phys(entry);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also get entries for higher levels (for huge pages or unmapped levels), so the pte_* names are not completely accurate. The functions themselves probably also need to depend on the level as noted above.


static inline uint64_t protnone_mask(uint64_t val)
{
return __pte_needs_invert(val) ? ~0ull : 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory, ~0ull could be a different size than uint64_t, so I'd feel better about:

Suggested change
return __pte_needs_invert(val) ? ~0ull : 0;
return __pte_needs_invert(val) ? -1 : 0;

Comment on lines +585 to +598
static inline bool __pte_needs_invert(uint64_t val)
{
return val && !(val & _PAGE_PRESENT);
}

static inline uint64_t protnone_mask(uint64_t val)
{
return __pte_needs_invert(val) ? ~0ull : 0;
}

static inline uint64_t pte_flags(uint64_t pte)
{
return pte & ((1 << PAGE_SHIFT) - 1);
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to fold these small helpers into their callers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't access user address
2 participants