Skip to content

Commit 620b4e9

Browse files
Matthew Wilcoxtorvalds
authored andcommitted
s390: use _refcount for pgtables
Patch series "Rearrange struct page", v6. As presented at LSFMM, this patch-set rearranges struct page to give more contiguous usable space to users who have allocated a struct page for their own purposes. For a graphical view of before-and-after, see the first two tabs of https://docs.google.com/spreadsheets/d/1tvCszs_7FXrjei9_mtFiKV6nW1FLnYyvPvW-qNZhdog/edit?usp=sharing Highlights: - deferred_list now really exists in struct page instead of just a comment. - hmm_data also exists in struct page instead of being a nasty hack. - x86's PGD pages have a real pointer to the mm_struct. - VMalloc pages now have all sorts of extra information stored in them to help with debugging and tuning. - rcu_head is no longer tied to slab in case anyone else wants to free pages by RCU. - slub's counters no longer share space with _refcount. - slub's freelist+counters are now naturally dword aligned. - slub loses a parameter to a lot of functions and a sysfs file. This patch (of 17): s390 borrows the storage used for _mapcount in struct page in order to account whether the bottom or top half is being used for 2kB page tables. I want to use that for something else, so use the top byte of _refcount instead of the bottom byte of _mapcount. _refcount may temporarily be incremented by other CPUs that see a stale pointer to this page in the page cache, but each CPU can only increment it by one, and there are no systems with 2^24 CPUs today, so they will not change the upper byte of _refcount. We do have to be a little careful not to lose any of their writes (as they will subsequently decrement the counter). Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Matthew Wilcox <[email protected]> Acked-by: Martin Schwidefsky <[email protected]> Cc: "Kirill A . Shutemov" <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Lai Jiangshan <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Jérôme Glisse <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: Andrey Ryabinin <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent e67d4ca commit 620b4e9

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

arch/s390/mm/pgalloc.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,15 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
190190
if (!list_empty(&mm->context.pgtable_list)) {
191191
page = list_first_entry(&mm->context.pgtable_list,
192192
struct page, lru);
193-
mask = atomic_read(&page->_mapcount);
193+
mask = atomic_read(&page->_refcount) >> 24;
194194
mask = (mask | (mask >> 4)) & 3;
195195
if (mask != 3) {
196196
table = (unsigned long *) page_to_phys(page);
197197
bit = mask & 1; /* =1 -> second 2K */
198198
if (bit)
199199
table += PTRS_PER_PTE;
200-
atomic_xor_bits(&page->_mapcount, 1U << bit);
200+
atomic_xor_bits(&page->_refcount,
201+
1U << (bit + 24));
201202
list_del(&page->lru);
202203
}
203204
}
@@ -218,12 +219,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
218219
table = (unsigned long *) page_to_phys(page);
219220
if (mm_alloc_pgste(mm)) {
220221
/* Return 4K page table with PGSTEs */
221-
atomic_set(&page->_mapcount, 3);
222+
atomic_xor_bits(&page->_refcount, 3 << 24);
222223
memset64((u64 *)table, _PAGE_INVALID, PTRS_PER_PTE);
223224
memset64((u64 *)table + PTRS_PER_PTE, 0, PTRS_PER_PTE);
224225
} else {
225226
/* Return the first 2K fragment of the page */
226-
atomic_set(&page->_mapcount, 1);
227+
atomic_xor_bits(&page->_refcount, 1 << 24);
227228
memset64((u64 *)table, _PAGE_INVALID, 2 * PTRS_PER_PTE);
228229
spin_lock_bh(&mm->context.lock);
229230
list_add(&page->lru, &mm->context.pgtable_list);
@@ -242,7 +243,8 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
242243
/* Free 2K page table fragment of a 4K page */
243244
bit = (__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
244245
spin_lock_bh(&mm->context.lock);
245-
mask = atomic_xor_bits(&page->_mapcount, 1U << bit);
246+
mask = atomic_xor_bits(&page->_refcount, 1U << (bit + 24));
247+
mask >>= 24;
246248
if (mask & 3)
247249
list_add(&page->lru, &mm->context.pgtable_list);
248250
else
@@ -253,7 +255,6 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
253255
}
254256

255257
pgtable_page_dtor(page);
256-
atomic_set(&page->_mapcount, -1);
257258
__free_page(page);
258259
}
259260

@@ -274,7 +275,8 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table,
274275
}
275276
bit = (__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t));
276277
spin_lock_bh(&mm->context.lock);
277-
mask = atomic_xor_bits(&page->_mapcount, 0x11U << bit);
278+
mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));
279+
mask >>= 24;
278280
if (mask & 3)
279281
list_add_tail(&page->lru, &mm->context.pgtable_list);
280282
else
@@ -296,12 +298,13 @@ static void __tlb_remove_table(void *_table)
296298
break;
297299
case 1: /* lower 2K of a 4K page table */
298300
case 2: /* higher 2K of a 4K page table */
299-
if (atomic_xor_bits(&page->_mapcount, mask << 4) != 0)
301+
mask = atomic_xor_bits(&page->_refcount, mask << (4 + 24));
302+
mask >>= 24;
303+
if (mask != 0)
300304
break;
301305
/* fallthrough */
302306
case 3: /* 4K page table with pgstes */
303307
pgtable_page_dtor(page);
304-
atomic_set(&page->_mapcount, -1);
305308
__free_page(page);
306309
break;
307310
}

0 commit comments

Comments
 (0)