Commit d8f299c2 authored by Andrew Morton's avatar Andrew Morton Committed by David S. Miller

[PATCH] move_one_page atomicity fix

The atomicicty fix for move_one_page() was not quite right.

We only do the page_table_present() test if CONFIG_HIGHPTE=y.  Which is
fine, but even with CONFIG_HIGHPTE=n, the pte mapping functions still
do an inc_preempt_count() due to their unconditional kmap_atomic().  So
we get a might_sleep() warning.

The warning is actually bogus, because those pte's are always in
direct-mapped memory.

So hm.  Three fixes suggest themselves:

1: Run the page_table_present() test if CONFIG_HIGHMEM.

   Rejected: penalises non-pte_highmem setups

2: Make kmap_atomic() not do inc_preempt_count() is the page was
   direct mapped.

   Rejected: I don't think we want kmap_atomic side effects to be
   varying according to the page which was passed.

3: Change the pte mapping functions so they don't run kmap_atomic at
   all if CONFIG_HIGHPTE=n

   This is what I did.  And guess what?  For CONFIG_HIGHMEM=y,
   CONFIG_HIGHPTE=n this patch shrinks the kernel by 5 kbytes.  Because
   kmap_atomic is inlined.

   The lesson: we do way too much damn inlining.
parent f0f5d073
...@@ -259,12 +259,21 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ...@@ -259,12 +259,21 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir, address) \ #define pte_offset_kernel(dir, address) \
((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address))
#if defined(CONFIG_HIGHPTE)
#define pte_offset_map(dir, address) \ #define pte_offset_map(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address)) ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address))
#define pte_offset_map_nested(dir, address) \ #define pte_offset_map_nested(dir, address) \
((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address)) ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address))
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0) #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1) #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
#else
#define pte_offset_map(dir, address) \
((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
#endif
#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G) #if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G)
typedef u32 pte_addr_t; typedef u32 pte_addr_t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment