Messages in this thread Patch in this message |  | | From | KOSAKI Motohiro <> | | Subject | [PATCH 2/7] Introduce __page_check_address | | Date | Fri, 4 Dec 2009 17:42:15 +0900 (JST) |
| |
From 381108e1ff6309f45f45a67acf2a1dd66e41df4f Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Date: Thu, 3 Dec 2009 15:01:42 +0900 Subject: [PATCH 2/7] Introduce __page_check_address
page_check_address() need to take ptelock. but it might be contended. Then we need trylock version and this patch introduce new helper function.
it will be used latter patch.
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> --- mm/rmap.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 49 insertions(+), 13 deletions(-)
diff --git a/mm/rmap.c b/mm/rmap.c index 278cd27..1b50425 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -268,44 +268,80 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma) * the page table lock when the pte is not present (helpful when reclaiming * highly shared pages). * - * On success returns with pte mapped and locked. + * if @noblock is true, page_check_address may return -EAGAIN if lock is + * contended. + * + * Returns valid pte pointer if success. + * Returns -EFAULT if address seems invalid. + * Returns -EAGAIN if trylock failed. */ -pte_t *page_check_address(struct page *page, struct mm_struct *mm, - unsigned long address, spinlock_t **ptlp, int sync) +static pte_t *__page_check_address(struct page *page, struct mm_struct *mm, + unsigned long address, spinlock_t **ptlp, + int sync, int noblock) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; spinlock_t *ptl; + int err = -EFAULT; pgd = pgd_offset(mm, address); if (!pgd_present(*pgd)) - return NULL; + goto out; pud = pud_offset(pgd, address); if (!pud_present(*pud)) - return NULL; + goto out; pmd = pmd_offset(pud, address); if (!pmd_present(*pmd)) - return NULL; + goto out; pte = pte_offset_map(pmd, address); /* Make a quick check before getting the lock */ - if (!sync && !pte_present(*pte)) { - pte_unmap(pte); - return NULL; - } + if (!sync && !pte_present(*pte)) + goto out_unmap; ptl = pte_lockptr(mm, pmd); - spin_lock(ptl); + if (noblock) { + if (!spin_trylock(ptl)) { + err = -EAGAIN; + goto out_unmap; + } + } else + spin_lock(ptl); + if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) { *ptlp = ptl; return pte; } - pte_unmap_unlock(pte, ptl); - return NULL; + + spin_unlock(ptl); + out_unmap: + pte_unmap(pte); + out: + return ERR_PTR(err); +} + +/* + * Check that @page is mapped at @address into @mm. + * + * If @sync is false, page_check_address may perform a racy check to avoid + * the page table lock when the pte is not present (helpful when reclaiming + * highly shared pages). + * + * On success returns with pte mapped and locked. + */ +pte_t *page_check_address(struct page *page, struct mm_struct *mm, + unsigned long address, spinlock_t **ptlp, int sync) +{ + pte_t *pte; + + pte = __page_check_address(page, mm, address, ptlp, sync, 0); + if (IS_ERR(pte)) + return NULL; + return pte; } /** -- 1.6.5.2
|  |