aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2013-11-14 17:31:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-14 19:32:20 -0500
commit49076ec2ccaf68610aa03d96bced9a6694b93ca1 (patch)
tree876564edb5cd164c7f9eaf39008f8f01fb164db6 /include/linux
parentf820e2805c7acb157a78438d07e47f4fc57fe679 (diff)
mm: dynamically allocate page->ptl if it cannot be embedded to struct page
If split page table lock is in use, we embed the lock into struct page of table's page. We have to disable split lock, if spinlock_t is too big be to be embedded, like when DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC enabled. This patch add support for dynamic allocation of split page table lock if we can't embed it to struct page. page->ptl is unsigned long now and we use it as spinlock_t if sizeof(spinlock_t) <= sizeof(long), otherwise it's pointer to spinlock_t. The spinlock_t allocated in pgtable_page_ctor() for PTE table and in pgtable_pmd_page_ctor() for PMD table. All other helpers converted to support dynamically allocated page->ptl. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Reviewed-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mm.h81
-rw-r--r--include/linux/mm_types.h5
2 files changed, 65 insertions, 21 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e855351c3361..d0339741b6ce 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1317,32 +1317,73 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
1317#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */ 1317#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
1318 1318
1319#if USE_SPLIT_PTE_PTLOCKS 1319#if USE_SPLIT_PTE_PTLOCKS
1320/* 1320bool __ptlock_alloc(struct page *page);
1321 * We tuck a spinlock to guard each pagetable page into its struct page, 1321void __ptlock_free(struct page *page);
1322 * at page->private, with BUILD_BUG_ON to make sure that this will not 1322static inline bool ptlock_alloc(struct page *page)
1323 * overflow into the next struct page (as it might with DEBUG_SPINLOCK). 1323{
1324 * When freeing, reset page->mapping so free_pages_check won't complain. 1324 if (sizeof(spinlock_t) > sizeof(page->ptl))
1325 */ 1325 return __ptlock_alloc(page);
1326#define __pte_lockptr(page) &((page)->ptl) 1326 return true;
1327#define pte_lock_init(_page) do { \ 1327}
1328 spin_lock_init(__pte_lockptr(_page)); \ 1328static inline void ptlock_free(struct page *page)
1329} while (0) 1329{
1330#define pte_lock_deinit(page) ((page)->mapping = NULL) 1330 if (sizeof(spinlock_t) > sizeof(page->ptl))
1331#define pte_lockptr(mm, pmd) ({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));}) 1331 __ptlock_free(page);
1332}
1333
1334static inline spinlock_t *ptlock_ptr(struct page *page)
1335{
1336 if (sizeof(spinlock_t) > sizeof(page->ptl))
1337 return (spinlock_t *) page->ptl;
1338 else
1339 return (spinlock_t *) &page->ptl;
1340}
1341
1342static inline spinlock_t *pte_lockptr(struct mm_struct *mm, pmd_t *pmd)
1343{
1344 return ptlock_ptr(pmd_page(*pmd));
1345}
1346
1347static inline bool ptlock_init(struct page *page)
1348{
1349 /*
1350 * prep_new_page() initialize page->private (and therefore page->ptl)
1351 * with 0. Make sure nobody took it in use in between.
1352 *
1353 * It can happen if arch try to use slab for page table allocation:
1354 * slab code uses page->slab_cache and page->first_page (for tail
1355 * pages), which share storage with page->ptl.
1356 */
1357 VM_BUG_ON(page->ptl);
1358 if (!ptlock_alloc(page))
1359 return false;
1360 spin_lock_init(ptlock_ptr(page));
1361 return true;
1362}
1363
1364/* Reset page->mapping so free_pages_check won't complain. */
1365static inline void pte_lock_deinit(struct page *page)
1366{
1367 page->mapping = NULL;
1368 ptlock_free(page);
1369}
1370
1332#else /* !USE_SPLIT_PTE_PTLOCKS */ 1371#else /* !USE_SPLIT_PTE_PTLOCKS */
1333/* 1372/*
1334 * We use mm->page_table_lock to guard all pagetable pages of the mm. 1373 * We use mm->page_table_lock to guard all pagetable pages of the mm.
1335 */ 1374 */
1336#define pte_lock_init(page) do {} while (0) 1375static inline spinlock_t *pte_lockptr(struct mm_struct *mm, pmd_t *pmd)
1337#define pte_lock_deinit(page) do {} while (0) 1376{
1338#define pte_lockptr(mm, pmd) ({(void)(pmd); &(mm)->page_table_lock;}) 1377 return &mm->page_table_lock;
1378}
1379static inline bool ptlock_init(struct page *page) { return true; }
1380static inline void pte_lock_deinit(struct page *page) {}
1339#endif /* USE_SPLIT_PTE_PTLOCKS */ 1381#endif /* USE_SPLIT_PTE_PTLOCKS */
1340 1382
1341static inline bool pgtable_page_ctor(struct page *page) 1383static inline bool pgtable_page_ctor(struct page *page)
1342{ 1384{
1343 pte_lock_init(page);
1344 inc_zone_page_state(page, NR_PAGETABLE); 1385 inc_zone_page_state(page, NR_PAGETABLE);
1345 return true; 1386 return ptlock_init(page);
1346} 1387}
1347 1388
1348static inline void pgtable_page_dtor(struct page *page) 1389static inline void pgtable_page_dtor(struct page *page)
@@ -1383,16 +1424,15 @@ static inline void pgtable_page_dtor(struct page *page)
1383 1424
1384static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd) 1425static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd)
1385{ 1426{
1386 return &virt_to_page(pmd)->ptl; 1427 return ptlock_ptr(virt_to_page(pmd));
1387} 1428}
1388 1429
1389static inline bool pgtable_pmd_page_ctor(struct page *page) 1430static inline bool pgtable_pmd_page_ctor(struct page *page)
1390{ 1431{
1391 spin_lock_init(&page->ptl);
1392#ifdef CONFIG_TRANSPARENT_HUGEPAGE 1432#ifdef CONFIG_TRANSPARENT_HUGEPAGE
1393 page->pmd_huge_pte = NULL; 1433 page->pmd_huge_pte = NULL;
1394#endif 1434#endif
1395 return true; 1435 return ptlock_init(page);
1396} 1436}
1397 1437
1398static inline void pgtable_pmd_page_dtor(struct page *page) 1438static inline void pgtable_pmd_page_dtor(struct page *page)
@@ -1400,6 +1440,7 @@ static inline void pgtable_pmd_page_dtor(struct page *page)
1400#ifdef CONFIG_TRANSPARENT_HUGEPAGE 1440#ifdef CONFIG_TRANSPARENT_HUGEPAGE
1401 VM_BUG_ON(page->pmd_huge_pte); 1441 VM_BUG_ON(page->pmd_huge_pte);
1402#endif 1442#endif
1443 ptlock_free(page);
1403} 1444}
1404 1445
1405#define pmd_huge_pte(mm, pmd) (virt_to_page(pmd)->pmd_huge_pte) 1446#define pmd_huge_pte(mm, pmd) (virt_to_page(pmd)->pmd_huge_pte)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 934261099975..423da79877e6 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -147,7 +147,10 @@ struct page {
147 * system if PG_buddy is set. 147 * system if PG_buddy is set.
148 */ 148 */
149#if USE_SPLIT_PTE_PTLOCKS 149#if USE_SPLIT_PTE_PTLOCKS
150 spinlock_t ptl; 150 unsigned long ptl; /* It's spinlock_t if it fits to long,
151 * otherwise it's pointer to dynamicaly
152 * allocated spinlock_t.
153 */
151#endif 154#endif
152 struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */ 155 struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */
153 struct page *first_page; /* Compound tail pages */ 156 struct page *first_page; /* Compound tail pages */