diff options
author | Hugh Dickins <hugh@veritas.com> | 2005-10-29 21:16:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 00:40:42 -0400 |
commit | 4c21e2f2441dc5fbb957b030333f5a3f2d02dea7 (patch) | |
tree | 1f76d33bb1d76221c6424bc5fed080a4f91349a6 /mm | |
parent | b38c6845b695141259019e2b7c0fe6c32a6e720d (diff) |
[PATCH] mm: split page table lock
Christoph Lameter demonstrated very poor scalability on the SGI 512-way, with
a many-threaded application which concurrently initializes different parts of
a large anonymous area.
This patch corrects that, by using a separate spinlock per page table page, to
guard the page table entries in that page, instead of using the mm's single
page_table_lock. (But even then, page_table_lock is still used to guard page
table allocation, and anon_vma allocation.)
In this implementation, the spinlock is tucked inside the struct page of the
page table page: with a BUILD_BUG_ON in case it overflows - which it would in
the case of 32-bit PA-RISC with spinlock debugging enabled.
Splitting the lock is not quite for free: another cacheline access. Ideally,
I suppose we would use split ptlock only for multi-threaded processes on
multi-cpu machines; but deciding that dynamically would have its own costs.
So for now enable it by config, at some number of cpus - since the Kconfig
language doesn't support inequalities, let preprocessor compare that with
NR_CPUS. But I don't think it's worth being user-configurable: for good
testing of both split and unsplit configs, split now at 4 cpus, and perhaps
change that to 8 later.
There is a benefit even for singly threaded processes: kswapd can be attacking
one part of the mm while another part is busy faulting.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/Kconfig | 13 | ||||
-rw-r--r-- | mm/filemap.c | 2 | ||||
-rw-r--r-- | mm/memory.c | 24 | ||||
-rw-r--r-- | mm/mremap.c | 11 | ||||
-rw-r--r-- | mm/page_alloc.c | 16 | ||||
-rw-r--r-- | mm/page_io.c | 6 | ||||
-rw-r--r-- | mm/rmap.c | 4 | ||||
-rw-r--r-- | mm/shmem.c | 22 | ||||
-rw-r--r-- | mm/swap.c | 2 | ||||
-rw-r--r-- | mm/swap_state.c | 8 | ||||
-rw-r--r-- | mm/swapfile.c | 12 | ||||
-rw-r--r-- | mm/vmscan.c | 2 |
12 files changed, 74 insertions, 48 deletions
diff --git a/mm/Kconfig b/mm/Kconfig index 391ffc54d136..f35a550ba4b9 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -111,3 +111,16 @@ config SPARSEMEM_STATIC | |||
111 | config SPARSEMEM_EXTREME | 111 | config SPARSEMEM_EXTREME |
112 | def_bool y | 112 | def_bool y |
113 | depends on SPARSEMEM && !SPARSEMEM_STATIC | 113 | depends on SPARSEMEM && !SPARSEMEM_STATIC |
114 | |||
115 | # Heavily threaded applications may benefit from splitting the mm-wide | ||
116 | # page_table_lock, so that faults on different parts of the user address | ||
117 | # space can be handled with less contention: split it at this NR_CPUS. | ||
118 | # Default to 4 for wider testing, though 8 might be more appropriate. | ||
119 | # ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. | ||
120 | # PA-RISC's debug spinlock_t is too large for the 32-bit struct page. | ||
121 | # | ||
122 | config SPLIT_PTLOCK_CPUS | ||
123 | int | ||
124 | default "4096" if ARM && !CPU_CACHE_VIPT | ||
125 | default "4096" if PARISC && DEBUG_SPINLOCK && !64BIT | ||
126 | default "4" | ||
diff --git a/mm/filemap.c b/mm/filemap.c index 8aa344e88489..f560b41c8f61 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -152,7 +152,7 @@ static int sync_page(void *word) | |||
152 | * in the ->sync_page() methods make essential use of the | 152 | * in the ->sync_page() methods make essential use of the |
153 | * page_mapping(), merely passing the page down to the backing | 153 | * page_mapping(), merely passing the page down to the backing |
154 | * device's unplug functions when it's non-NULL, which in turn | 154 | * device's unplug functions when it's non-NULL, which in turn |
155 | * ignore it for all cases but swap, where only page->private is | 155 | * ignore it for all cases but swap, where only page_private(page) is |
156 | * of interest. When page_mapping() does go NULL, the entire | 156 | * of interest. When page_mapping() does go NULL, the entire |
157 | * call stack gracefully ignores the page and returns. | 157 | * call stack gracefully ignores the page and returns. |
158 | * -- wli | 158 | * -- wli |
diff --git a/mm/memory.c b/mm/memory.c index 8461e2dd91d7..e9ef599498b5 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -114,6 +114,7 @@ static void free_pte_range(struct mmu_gather *tlb, pmd_t *pmd) | |||
114 | { | 114 | { |
115 | struct page *page = pmd_page(*pmd); | 115 | struct page *page = pmd_page(*pmd); |
116 | pmd_clear(pmd); | 116 | pmd_clear(pmd); |
117 | pte_lock_deinit(page); | ||
117 | pte_free_tlb(tlb, page); | 118 | pte_free_tlb(tlb, page); |
118 | dec_page_state(nr_page_table_pages); | 119 | dec_page_state(nr_page_table_pages); |
119 | tlb->mm->nr_ptes--; | 120 | tlb->mm->nr_ptes--; |
@@ -294,10 +295,12 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) | |||
294 | if (!new) | 295 | if (!new) |
295 | return -ENOMEM; | 296 | return -ENOMEM; |
296 | 297 | ||
298 | pte_lock_init(new); | ||
297 | spin_lock(&mm->page_table_lock); | 299 | spin_lock(&mm->page_table_lock); |
298 | if (pmd_present(*pmd)) /* Another has populated it */ | 300 | if (pmd_present(*pmd)) { /* Another has populated it */ |
301 | pte_lock_deinit(new); | ||
299 | pte_free(new); | 302 | pte_free(new); |
300 | else { | 303 | } else { |
301 | mm->nr_ptes++; | 304 | mm->nr_ptes++; |
302 | inc_page_state(nr_page_table_pages); | 305 | inc_page_state(nr_page_table_pages); |
303 | pmd_populate(mm, pmd, new); | 306 | pmd_populate(mm, pmd, new); |
@@ -432,7 +435,7 @@ again: | |||
432 | if (!dst_pte) | 435 | if (!dst_pte) |
433 | return -ENOMEM; | 436 | return -ENOMEM; |
434 | src_pte = pte_offset_map_nested(src_pmd, addr); | 437 | src_pte = pte_offset_map_nested(src_pmd, addr); |
435 | src_ptl = &src_mm->page_table_lock; | 438 | src_ptl = pte_lockptr(src_mm, src_pmd); |
436 | spin_lock(src_ptl); | 439 | spin_lock(src_ptl); |
437 | 440 | ||
438 | do { | 441 | do { |
@@ -1194,15 +1197,16 @@ EXPORT_SYMBOL(remap_pfn_range); | |||
1194 | * (but do_wp_page is only called after already making such a check; | 1197 | * (but do_wp_page is only called after already making such a check; |
1195 | * and do_anonymous_page and do_no_page can safely check later on). | 1198 | * and do_anonymous_page and do_no_page can safely check later on). |
1196 | */ | 1199 | */ |
1197 | static inline int pte_unmap_same(struct mm_struct *mm, | 1200 | static inline int pte_unmap_same(struct mm_struct *mm, pmd_t *pmd, |
1198 | pte_t *page_table, pte_t orig_pte) | 1201 | pte_t *page_table, pte_t orig_pte) |
1199 | { | 1202 | { |
1200 | int same = 1; | 1203 | int same = 1; |
1201 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) | 1204 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) |
1202 | if (sizeof(pte_t) > sizeof(unsigned long)) { | 1205 | if (sizeof(pte_t) > sizeof(unsigned long)) { |
1203 | spin_lock(&mm->page_table_lock); | 1206 | spinlock_t *ptl = pte_lockptr(mm, pmd); |
1207 | spin_lock(ptl); | ||
1204 | same = pte_same(*page_table, orig_pte); | 1208 | same = pte_same(*page_table, orig_pte); |
1205 | spin_unlock(&mm->page_table_lock); | 1209 | spin_unlock(ptl); |
1206 | } | 1210 | } |
1207 | #endif | 1211 | #endif |
1208 | pte_unmap(page_table); | 1212 | pte_unmap(page_table); |
@@ -1655,7 +1659,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1655 | pte_t pte; | 1659 | pte_t pte; |
1656 | int ret = VM_FAULT_MINOR; | 1660 | int ret = VM_FAULT_MINOR; |
1657 | 1661 | ||
1658 | if (!pte_unmap_same(mm, page_table, orig_pte)) | 1662 | if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) |
1659 | goto out; | 1663 | goto out; |
1660 | 1664 | ||
1661 | entry = pte_to_swp_entry(orig_pte); | 1665 | entry = pte_to_swp_entry(orig_pte); |
@@ -1773,7 +1777,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1773 | page_cache_get(page); | 1777 | page_cache_get(page); |
1774 | entry = mk_pte(page, vma->vm_page_prot); | 1778 | entry = mk_pte(page, vma->vm_page_prot); |
1775 | 1779 | ||
1776 | ptl = &mm->page_table_lock; | 1780 | ptl = pte_lockptr(mm, pmd); |
1777 | spin_lock(ptl); | 1781 | spin_lock(ptl); |
1778 | if (!pte_none(*page_table)) | 1782 | if (!pte_none(*page_table)) |
1779 | goto release; | 1783 | goto release; |
@@ -1934,7 +1938,7 @@ static int do_file_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
1934 | pgoff_t pgoff; | 1938 | pgoff_t pgoff; |
1935 | int err; | 1939 | int err; |
1936 | 1940 | ||
1937 | if (!pte_unmap_same(mm, page_table, orig_pte)) | 1941 | if (!pte_unmap_same(mm, pmd, page_table, orig_pte)) |
1938 | return VM_FAULT_MINOR; | 1942 | return VM_FAULT_MINOR; |
1939 | 1943 | ||
1940 | if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) { | 1944 | if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) { |
@@ -1992,7 +1996,7 @@ static inline int handle_pte_fault(struct mm_struct *mm, | |||
1992 | pte, pmd, write_access, entry); | 1996 | pte, pmd, write_access, entry); |
1993 | } | 1997 | } |
1994 | 1998 | ||
1995 | ptl = &mm->page_table_lock; | 1999 | ptl = pte_lockptr(mm, pmd); |
1996 | spin_lock(ptl); | 2000 | spin_lock(ptl); |
1997 | if (unlikely(!pte_same(*pte, entry))) | 2001 | if (unlikely(!pte_same(*pte, entry))) |
1998 | goto unlock; | 2002 | goto unlock; |
diff --git a/mm/mremap.c b/mm/mremap.c index 8de77b632a20..b535438c363c 100644 --- a/mm/mremap.c +++ b/mm/mremap.c | |||
@@ -72,7 +72,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
72 | struct address_space *mapping = NULL; | 72 | struct address_space *mapping = NULL; |
73 | struct mm_struct *mm = vma->vm_mm; | 73 | struct mm_struct *mm = vma->vm_mm; |
74 | pte_t *old_pte, *new_pte, pte; | 74 | pte_t *old_pte, *new_pte, pte; |
75 | spinlock_t *old_ptl; | 75 | spinlock_t *old_ptl, *new_ptl; |
76 | 76 | ||
77 | if (vma->vm_file) { | 77 | if (vma->vm_file) { |
78 | /* | 78 | /* |
@@ -88,8 +88,15 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
88 | new_vma->vm_truncate_count = 0; | 88 | new_vma->vm_truncate_count = 0; |
89 | } | 89 | } |
90 | 90 | ||
91 | /* | ||
92 | * We don't have to worry about the ordering of src and dst | ||
93 | * pte locks because exclusive mmap_sem prevents deadlock. | ||
94 | */ | ||
91 | old_pte = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl); | 95 | old_pte = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl); |
92 | new_pte = pte_offset_map_nested(new_pmd, new_addr); | 96 | new_pte = pte_offset_map_nested(new_pmd, new_addr); |
97 | new_ptl = pte_lockptr(mm, new_pmd); | ||
98 | if (new_ptl != old_ptl) | ||
99 | spin_lock(new_ptl); | ||
93 | 100 | ||
94 | for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE, | 101 | for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE, |
95 | new_pte++, new_addr += PAGE_SIZE) { | 102 | new_pte++, new_addr += PAGE_SIZE) { |
@@ -101,6 +108,8 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd, | |||
101 | set_pte_at(mm, new_addr, new_pte, pte); | 108 | set_pte_at(mm, new_addr, new_pte, pte); |
102 | } | 109 | } |
103 | 110 | ||
111 | if (new_ptl != old_ptl) | ||
112 | spin_unlock(new_ptl); | ||
104 | pte_unmap_nested(new_pte - 1); | 113 | pte_unmap_nested(new_pte - 1); |
105 | pte_unmap_unlock(old_pte - 1, old_ptl); | 114 | pte_unmap_unlock(old_pte - 1, old_ptl); |
106 | if (mapping) | 115 | if (mapping) |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0541288ebf4b..a2995a5d012c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -154,7 +154,7 @@ static void prep_compound_page(struct page *page, unsigned long order) | |||
154 | struct page *p = page + i; | 154 | struct page *p = page + i; |
155 | 155 | ||
156 | SetPageCompound(p); | 156 | SetPageCompound(p); |
157 | p->private = (unsigned long)page; | 157 | set_page_private(p, (unsigned long)page); |
158 | } | 158 | } |
159 | } | 159 | } |
160 | 160 | ||
@@ -174,7 +174,7 @@ static void destroy_compound_page(struct page *page, unsigned long order) | |||
174 | 174 | ||
175 | if (!PageCompound(p)) | 175 | if (!PageCompound(p)) |
176 | bad_page(__FUNCTION__, page); | 176 | bad_page(__FUNCTION__, page); |
177 | if (p->private != (unsigned long)page) | 177 | if (page_private(p) != (unsigned long)page) |
178 | bad_page(__FUNCTION__, page); | 178 | bad_page(__FUNCTION__, page); |
179 | ClearPageCompound(p); | 179 | ClearPageCompound(p); |
180 | } | 180 | } |
@@ -187,18 +187,18 @@ static void destroy_compound_page(struct page *page, unsigned long order) | |||
187 | * So, we don't need atomic page->flags operations here. | 187 | * So, we don't need atomic page->flags operations here. |
188 | */ | 188 | */ |
189 | static inline unsigned long page_order(struct page *page) { | 189 | static inline unsigned long page_order(struct page *page) { |
190 | return page->private; | 190 | return page_private(page); |
191 | } | 191 | } |
192 | 192 | ||
193 | static inline void set_page_order(struct page *page, int order) { | 193 | static inline void set_page_order(struct page *page, int order) { |
194 | page->private = order; | 194 | set_page_private(page, order); |
195 | __SetPagePrivate(page); | 195 | __SetPagePrivate(page); |
196 | } | 196 | } |
197 | 197 | ||
198 | static inline void rmv_page_order(struct page *page) | 198 | static inline void rmv_page_order(struct page *page) |
199 | { | 199 | { |
200 | __ClearPagePrivate(page); | 200 | __ClearPagePrivate(page); |
201 | page->private = 0; | 201 | set_page_private(page, 0); |
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
@@ -238,7 +238,7 @@ __find_combined_index(unsigned long page_idx, unsigned int order) | |||
238 | * (a) the buddy is free && | 238 | * (a) the buddy is free && |
239 | * (b) the buddy is on the buddy system && | 239 | * (b) the buddy is on the buddy system && |
240 | * (c) a page and its buddy have the same order. | 240 | * (c) a page and its buddy have the same order. |
241 | * for recording page's order, we use page->private and PG_private. | 241 | * for recording page's order, we use page_private(page) and PG_private. |
242 | * | 242 | * |
243 | */ | 243 | */ |
244 | static inline int page_is_buddy(struct page *page, int order) | 244 | static inline int page_is_buddy(struct page *page, int order) |
@@ -264,7 +264,7 @@ static inline int page_is_buddy(struct page *page, int order) | |||
264 | * parts of the VM system. | 264 | * parts of the VM system. |
265 | * At each level, we keep a list of pages, which are heads of continuous | 265 | * At each level, we keep a list of pages, which are heads of continuous |
266 | * free pages of length of (1 << order) and marked with PG_Private.Page's | 266 | * free pages of length of (1 << order) and marked with PG_Private.Page's |
267 | * order is recorded in page->private field. | 267 | * order is recorded in page_private(page) field. |
268 | * So when we are allocating or freeing one, we can derive the state of the | 268 | * So when we are allocating or freeing one, we can derive the state of the |
269 | * other. That is, if we allocate a small block, and both were | 269 | * other. That is, if we allocate a small block, and both were |
270 | * free, the remainder of the region must be split into blocks. | 270 | * free, the remainder of the region must be split into blocks. |
@@ -463,7 +463,7 @@ static void prep_new_page(struct page *page, int order) | |||
463 | page->flags &= ~(1 << PG_uptodate | 1 << PG_error | | 463 | page->flags &= ~(1 << PG_uptodate | 1 << PG_error | |
464 | 1 << PG_referenced | 1 << PG_arch_1 | | 464 | 1 << PG_referenced | 1 << PG_arch_1 | |
465 | 1 << PG_checked | 1 << PG_mappedtodisk); | 465 | 1 << PG_checked | 1 << PG_mappedtodisk); |
466 | page->private = 0; | 466 | set_page_private(page, 0); |
467 | set_page_refs(page, order); | 467 | set_page_refs(page, order); |
468 | kernel_map_pages(page, 1 << order, 1); | 468 | kernel_map_pages(page, 1 << order, 1); |
469 | } | 469 | } |
diff --git a/mm/page_io.c b/mm/page_io.c index 330e00d6db00..bb2b0d53889c 100644 --- a/mm/page_io.c +++ b/mm/page_io.c | |||
@@ -91,7 +91,8 @@ int swap_writepage(struct page *page, struct writeback_control *wbc) | |||
91 | unlock_page(page); | 91 | unlock_page(page); |
92 | goto out; | 92 | goto out; |
93 | } | 93 | } |
94 | bio = get_swap_bio(GFP_NOIO, page->private, page, end_swap_bio_write); | 94 | bio = get_swap_bio(GFP_NOIO, page_private(page), page, |
95 | end_swap_bio_write); | ||
95 | if (bio == NULL) { | 96 | if (bio == NULL) { |
96 | set_page_dirty(page); | 97 | set_page_dirty(page); |
97 | unlock_page(page); | 98 | unlock_page(page); |
@@ -115,7 +116,8 @@ int swap_readpage(struct file *file, struct page *page) | |||
115 | 116 | ||
116 | BUG_ON(!PageLocked(page)); | 117 | BUG_ON(!PageLocked(page)); |
117 | ClearPageUptodate(page); | 118 | ClearPageUptodate(page); |
118 | bio = get_swap_bio(GFP_KERNEL, page->private, page, end_swap_bio_read); | 119 | bio = get_swap_bio(GFP_KERNEL, page_private(page), page, |
120 | end_swap_bio_read); | ||
119 | if (bio == NULL) { | 121 | if (bio == NULL) { |
120 | unlock_page(page); | 122 | unlock_page(page); |
121 | ret = -ENOMEM; | 123 | ret = -ENOMEM; |
@@ -274,7 +274,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm, | |||
274 | return NULL; | 274 | return NULL; |
275 | } | 275 | } |
276 | 276 | ||
277 | ptl = &mm->page_table_lock; | 277 | ptl = pte_lockptr(mm, pmd); |
278 | spin_lock(ptl); | 278 | spin_lock(ptl); |
279 | if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) { | 279 | if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) { |
280 | *ptlp = ptl; | 280 | *ptlp = ptl; |
@@ -550,7 +550,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) | |||
550 | update_hiwater_rss(mm); | 550 | update_hiwater_rss(mm); |
551 | 551 | ||
552 | if (PageAnon(page)) { | 552 | if (PageAnon(page)) { |
553 | swp_entry_t entry = { .val = page->private }; | 553 | swp_entry_t entry = { .val = page_private(page) }; |
554 | /* | 554 | /* |
555 | * Store the swap location in the pte. | 555 | * Store the swap location in the pte. |
556 | * See handle_pte_fault() ... | 556 | * See handle_pte_fault() ... |
diff --git a/mm/shmem.c b/mm/shmem.c index 37777f4c11f8..dc25565a61e9 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -71,9 +71,6 @@ | |||
71 | /* Pretend that each entry is of this size in directory's i_size */ | 71 | /* Pretend that each entry is of this size in directory's i_size */ |
72 | #define BOGO_DIRENT_SIZE 20 | 72 | #define BOGO_DIRENT_SIZE 20 |
73 | 73 | ||
74 | /* Keep swapped page count in private field of indirect struct page */ | ||
75 | #define nr_swapped private | ||
76 | |||
77 | /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */ | 74 | /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */ |
78 | enum sgp_type { | 75 | enum sgp_type { |
79 | SGP_QUICK, /* don't try more than file page cache lookup */ | 76 | SGP_QUICK, /* don't try more than file page cache lookup */ |
@@ -324,8 +321,10 @@ static void shmem_swp_set(struct shmem_inode_info *info, swp_entry_t *entry, uns | |||
324 | 321 | ||
325 | entry->val = value; | 322 | entry->val = value; |
326 | info->swapped += incdec; | 323 | info->swapped += incdec; |
327 | if ((unsigned long)(entry - info->i_direct) >= SHMEM_NR_DIRECT) | 324 | if ((unsigned long)(entry - info->i_direct) >= SHMEM_NR_DIRECT) { |
328 | kmap_atomic_to_page(entry)->nr_swapped += incdec; | 325 | struct page *page = kmap_atomic_to_page(entry); |
326 | set_page_private(page, page_private(page) + incdec); | ||
327 | } | ||
329 | } | 328 | } |
330 | 329 | ||
331 | /* | 330 | /* |
@@ -368,9 +367,8 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long | |||
368 | 367 | ||
369 | spin_unlock(&info->lock); | 368 | spin_unlock(&info->lock); |
370 | page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO); | 369 | page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO); |
371 | if (page) { | 370 | if (page) |
372 | page->nr_swapped = 0; | 371 | set_page_private(page, 0); |
373 | } | ||
374 | spin_lock(&info->lock); | 372 | spin_lock(&info->lock); |
375 | 373 | ||
376 | if (!page) { | 374 | if (!page) { |
@@ -561,7 +559,7 @@ static void shmem_truncate(struct inode *inode) | |||
561 | diroff = 0; | 559 | diroff = 0; |
562 | } | 560 | } |
563 | subdir = dir[diroff]; | 561 | subdir = dir[diroff]; |
564 | if (subdir && subdir->nr_swapped) { | 562 | if (subdir && page_private(subdir)) { |
565 | size = limit - idx; | 563 | size = limit - idx; |
566 | if (size > ENTRIES_PER_PAGE) | 564 | if (size > ENTRIES_PER_PAGE) |
567 | size = ENTRIES_PER_PAGE; | 565 | size = ENTRIES_PER_PAGE; |
@@ -572,10 +570,10 @@ static void shmem_truncate(struct inode *inode) | |||
572 | nr_swaps_freed += freed; | 570 | nr_swaps_freed += freed; |
573 | if (offset) | 571 | if (offset) |
574 | spin_lock(&info->lock); | 572 | spin_lock(&info->lock); |
575 | subdir->nr_swapped -= freed; | 573 | set_page_private(subdir, page_private(subdir) - freed); |
576 | if (offset) | 574 | if (offset) |
577 | spin_unlock(&info->lock); | 575 | spin_unlock(&info->lock); |
578 | BUG_ON(subdir->nr_swapped > offset); | 576 | BUG_ON(page_private(subdir) > offset); |
579 | } | 577 | } |
580 | if (offset) | 578 | if (offset) |
581 | offset = 0; | 579 | offset = 0; |
@@ -743,7 +741,7 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s | |||
743 | dir = shmem_dir_map(subdir); | 741 | dir = shmem_dir_map(subdir); |
744 | } | 742 | } |
745 | subdir = *dir; | 743 | subdir = *dir; |
746 | if (subdir && subdir->nr_swapped) { | 744 | if (subdir && page_private(subdir)) { |
747 | ptr = shmem_swp_map(subdir); | 745 | ptr = shmem_swp_map(subdir); |
748 | size = limit - idx; | 746 | size = limit - idx; |
749 | if (size > ENTRIES_PER_PAGE) | 747 | if (size > ENTRIES_PER_PAGE) |
@@ -39,7 +39,7 @@ int page_cluster; | |||
39 | void put_page(struct page *page) | 39 | void put_page(struct page *page) |
40 | { | 40 | { |
41 | if (unlikely(PageCompound(page))) { | 41 | if (unlikely(PageCompound(page))) { |
42 | page = (struct page *)page->private; | 42 | page = (struct page *)page_private(page); |
43 | if (put_page_testzero(page)) { | 43 | if (put_page_testzero(page)) { |
44 | void (*dtor)(struct page *page); | 44 | void (*dtor)(struct page *page); |
45 | 45 | ||
diff --git a/mm/swap_state.c b/mm/swap_state.c index 132164f7d0a7..cafc1edcbeba 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c | |||
@@ -83,7 +83,7 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry, | |||
83 | page_cache_get(page); | 83 | page_cache_get(page); |
84 | SetPageLocked(page); | 84 | SetPageLocked(page); |
85 | SetPageSwapCache(page); | 85 | SetPageSwapCache(page); |
86 | page->private = entry.val; | 86 | set_page_private(page, entry.val); |
87 | total_swapcache_pages++; | 87 | total_swapcache_pages++; |
88 | pagecache_acct(1); | 88 | pagecache_acct(1); |
89 | } | 89 | } |
@@ -126,8 +126,8 @@ void __delete_from_swap_cache(struct page *page) | |||
126 | BUG_ON(PageWriteback(page)); | 126 | BUG_ON(PageWriteback(page)); |
127 | BUG_ON(PagePrivate(page)); | 127 | BUG_ON(PagePrivate(page)); |
128 | 128 | ||
129 | radix_tree_delete(&swapper_space.page_tree, page->private); | 129 | radix_tree_delete(&swapper_space.page_tree, page_private(page)); |
130 | page->private = 0; | 130 | set_page_private(page, 0); |
131 | ClearPageSwapCache(page); | 131 | ClearPageSwapCache(page); |
132 | total_swapcache_pages--; | 132 | total_swapcache_pages--; |
133 | pagecache_acct(-1); | 133 | pagecache_acct(-1); |
@@ -197,7 +197,7 @@ void delete_from_swap_cache(struct page *page) | |||
197 | { | 197 | { |
198 | swp_entry_t entry; | 198 | swp_entry_t entry; |
199 | 199 | ||
200 | entry.val = page->private; | 200 | entry.val = page_private(page); |
201 | 201 | ||
202 | write_lock_irq(&swapper_space.tree_lock); | 202 | write_lock_irq(&swapper_space.tree_lock); |
203 | __delete_from_swap_cache(page); | 203 | __delete_from_swap_cache(page); |
diff --git a/mm/swapfile.c b/mm/swapfile.c index 510f0039b000..8970c0b74194 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -61,7 +61,7 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) | |||
61 | swp_entry_t entry; | 61 | swp_entry_t entry; |
62 | 62 | ||
63 | down_read(&swap_unplug_sem); | 63 | down_read(&swap_unplug_sem); |
64 | entry.val = page->private; | 64 | entry.val = page_private(page); |
65 | if (PageSwapCache(page)) { | 65 | if (PageSwapCache(page)) { |
66 | struct block_device *bdev = swap_info[swp_type(entry)].bdev; | 66 | struct block_device *bdev = swap_info[swp_type(entry)].bdev; |
67 | struct backing_dev_info *bdi; | 67 | struct backing_dev_info *bdi; |
@@ -69,8 +69,8 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) | |||
69 | /* | 69 | /* |
70 | * If the page is removed from swapcache from under us (with a | 70 | * If the page is removed from swapcache from under us (with a |
71 | * racy try_to_unuse/swapoff) we need an additional reference | 71 | * racy try_to_unuse/swapoff) we need an additional reference |
72 | * count to avoid reading garbage from page->private above. If | 72 | * count to avoid reading garbage from page_private(page) above. |
73 | * the WARN_ON triggers during a swapoff it maybe the race | 73 | * If the WARN_ON triggers during a swapoff it maybe the race |
74 | * condition and it's harmless. However if it triggers without | 74 | * condition and it's harmless. However if it triggers without |
75 | * swapoff it signals a problem. | 75 | * swapoff it signals a problem. |
76 | */ | 76 | */ |
@@ -294,7 +294,7 @@ static inline int page_swapcount(struct page *page) | |||
294 | struct swap_info_struct *p; | 294 | struct swap_info_struct *p; |
295 | swp_entry_t entry; | 295 | swp_entry_t entry; |
296 | 296 | ||
297 | entry.val = page->private; | 297 | entry.val = page_private(page); |
298 | p = swap_info_get(entry); | 298 | p = swap_info_get(entry); |
299 | if (p) { | 299 | if (p) { |
300 | /* Subtract the 1 for the swap cache itself */ | 300 | /* Subtract the 1 for the swap cache itself */ |
@@ -339,7 +339,7 @@ int remove_exclusive_swap_page(struct page *page) | |||
339 | if (page_count(page) != 2) /* 2: us + cache */ | 339 | if (page_count(page) != 2) /* 2: us + cache */ |
340 | return 0; | 340 | return 0; |
341 | 341 | ||
342 | entry.val = page->private; | 342 | entry.val = page_private(page); |
343 | p = swap_info_get(entry); | 343 | p = swap_info_get(entry); |
344 | if (!p) | 344 | if (!p) |
345 | return 0; | 345 | return 0; |
@@ -1042,7 +1042,7 @@ int page_queue_congested(struct page *page) | |||
1042 | BUG_ON(!PageLocked(page)); /* It pins the swap_info_struct */ | 1042 | BUG_ON(!PageLocked(page)); /* It pins the swap_info_struct */ |
1043 | 1043 | ||
1044 | if (PageSwapCache(page)) { | 1044 | if (PageSwapCache(page)) { |
1045 | swp_entry_t entry = { .val = page->private }; | 1045 | swp_entry_t entry = { .val = page_private(page) }; |
1046 | struct swap_info_struct *sis; | 1046 | struct swap_info_struct *sis; |
1047 | 1047 | ||
1048 | sis = get_swap_info_struct(swp_type(entry)); | 1048 | sis = get_swap_info_struct(swp_type(entry)); |
diff --git a/mm/vmscan.c b/mm/vmscan.c index 41d1064aabfb..135bf8ca96ee 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
@@ -521,7 +521,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc) | |||
521 | 521 | ||
522 | #ifdef CONFIG_SWAP | 522 | #ifdef CONFIG_SWAP |
523 | if (PageSwapCache(page)) { | 523 | if (PageSwapCache(page)) { |
524 | swp_entry_t swap = { .val = page->private }; | 524 | swp_entry_t swap = { .val = page_private(page) }; |
525 | __delete_from_swap_cache(page); | 525 | __delete_from_swap_cache(page); |
526 | write_unlock_irq(&mapping->tree_lock); | 526 | write_unlock_irq(&mapping->tree_lock); |
527 | swap_free(swap); | 527 | swap_free(swap); |