Changing page attributes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, reading the source code of kmap_atomic() and kunmap_atomic() as
below, I would like to ask:

a.   noticed that pagefault_disable() and pagefault_enable() is called
across two different function - why is that necessary?

b.   basically, I would like to create a new page, and assign the PTE
to point to that page, and change the page attributes in the PTE - so
all these operation MUST ALWAYS BE done with pagefault disabled?

c.   Since within an interrupt, the interrupt is disabled, therefore,
I can always do these above operation inside the pagefault handler
context as well?

d.   After I get a new page with __get_free_page(__GFP_HIGHMEM), and
returned value is not null, it means that PTE mapping has already been
allocated to it, right?

e.   So if I want to change the page attributes inside the PTE from
(d), it should be done within pagefault_disabled mode?

f.   After I set the _PAGE_PRESENT bit of the PTE to invalid, and
since __get_free_page() derive the page from a free_list, will the
page ever be reused by the kernel, either for another allocation, or
for some other purposes?

Sorry, if these questions are confusing.....


==============================================================================

/*
 * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
 * no global lock is needed and because the kmap code must perform a global TLB
 * invalidation when the kmap pool wraps.
 *
 * However when holding an atomic kmap is is not legal to sleep, so atomic
 * kmaps are appropriate for short, tight code paths only.
 */
void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
{
        enum fixed_addresses idx;
        unsigned long vaddr;

        /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
        pagefault_disable();

        if (!PageHighMem(page))
                return page_address(page);

        debug_kmap_atomic_prot(type);

        idx = type + KM_TYPE_NR*smp_processor_id();
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
        BUG_ON(!pte_none(*(kmap_pte-idx)));
        set_pte(kmap_pte-idx, mk_pte(page, prot));
        arch_flush_lazy_mmu_mode();

        return (void *)vaddr;
}

void *kmap_atomic(struct page *page, enum km_type type)
{
        return kmap_atomic_prot(page, type, kmap_prot);
}

void kunmap_atomic(void *kvaddr, enum km_type type)
{
        unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
        enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();

        /*
         * Force other mappings to Oops if they'll try to access this pte
         * without first remap it.  Keeping stale mappings around is a bad idea
         * also, in case the page changes cacheability attributes or becomes
         * a protected page in a hypervisor.
         */
        if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
                kpte_clear_flush(kmap_pte-idx, vaddr);
        else {
#ifdef CONFIG_DEBUG_HIGHMEM
                BUG_ON(vaddr < PAGE_OFFSET);
                BUG_ON(vaddr >= (unsigned long)high_memory);
#endif
        }

        arch_flush_lazy_mmu_mode();
        pagefault_enable();
}



-- 
Regards,
Peter Teoh

--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux