diff options
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 16 | ||||
| -rw-r--r-- | arch/s390/mm/pgtable.c | 23 | ||||
| -rw-r--r-- | include/linux/page-flags.h | 2 |
3 files changed, 25 insertions, 16 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index c4773a2ef3d3..e4efacfe1b63 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -577,16 +577,16 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) | |||
| 577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) | 577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) |
| 578 | { | 578 | { |
| 579 | #ifdef CONFIG_PGSTE | 579 | #ifdef CONFIG_PGSTE |
| 580 | unsigned long pfn, bits; | 580 | unsigned long address, bits; |
| 581 | unsigned char skey; | 581 | unsigned char skey; |
| 582 | 582 | ||
| 583 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | 583 | address = pte_val(*ptep) & PAGE_MASK; |
| 584 | skey = page_get_storage_key(pfn); | 584 | skey = page_get_storage_key(address); |
| 585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); | 585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
| 586 | /* Clear page changed & referenced bit in the storage key */ | 586 | /* Clear page changed & referenced bit in the storage key */ |
| 587 | if (bits) { | 587 | if (bits) { |
| 588 | skey ^= bits; | 588 | skey ^= bits; |
| 589 | page_set_storage_key(pfn, skey, 1); | 589 | page_set_storage_key(address, skey, 1); |
| 590 | } | 590 | } |
| 591 | /* Transfer page changed & referenced bit to guest bits in pgste */ | 591 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
| 592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ | 592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ |
| @@ -628,16 +628,16 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | |||
| 628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) | 628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) |
| 629 | { | 629 | { |
| 630 | #ifdef CONFIG_PGSTE | 630 | #ifdef CONFIG_PGSTE |
| 631 | unsigned long pfn; | 631 | unsigned long address; |
| 632 | unsigned long okey, nkey; | 632 | unsigned long okey, nkey; |
| 633 | 633 | ||
| 634 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | 634 | address = pte_val(*ptep) & PAGE_MASK; |
| 635 | okey = nkey = page_get_storage_key(pfn); | 635 | okey = nkey = page_get_storage_key(address); |
| 636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); | 636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); |
| 637 | /* Set page access key and fetch protection bit from pgste */ | 637 | /* Set page access key and fetch protection bit from pgste */ |
| 638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; | 638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; |
| 639 | if (okey != nkey) | 639 | if (okey != nkey) |
| 640 | page_set_storage_key(pfn, nkey, 1); | 640 | page_set_storage_key(address, nkey, 1); |
| 641 | #endif | 641 | #endif |
| 642 | } | 642 | } |
| 643 | 643 | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 14c6fae6fe6b..b09763fe5da1 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -71,12 +71,15 @@ static void rcu_table_freelist_callback(struct rcu_head *head) | |||
| 71 | 71 | ||
| 72 | void rcu_table_freelist_finish(void) | 72 | void rcu_table_freelist_finish(void) |
| 73 | { | 73 | { |
| 74 | struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist); | 74 | struct rcu_table_freelist **batchp = &get_cpu_var(rcu_table_freelist); |
| 75 | struct rcu_table_freelist *batch = *batchp; | ||
| 75 | 76 | ||
| 76 | if (!batch) | 77 | if (!batch) |
| 77 | return; | 78 | goto out; |
| 78 | call_rcu(&batch->rcu, rcu_table_freelist_callback); | 79 | call_rcu(&batch->rcu, rcu_table_freelist_callback); |
| 79 | __get_cpu_var(rcu_table_freelist) = NULL; | 80 | *batchp = NULL; |
| 81 | out: | ||
| 82 | put_cpu_var(rcu_table_freelist); | ||
| 80 | } | 83 | } |
| 81 | 84 | ||
| 82 | static void smp_sync(void *arg) | 85 | static void smp_sync(void *arg) |
| @@ -141,20 +144,23 @@ void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
| 141 | { | 144 | { |
| 142 | struct rcu_table_freelist *batch; | 145 | struct rcu_table_freelist *batch; |
| 143 | 146 | ||
| 147 | preempt_disable(); | ||
| 144 | if (atomic_read(&mm->mm_users) < 2 && | 148 | if (atomic_read(&mm->mm_users) < 2 && |
| 145 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 149 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
| 146 | crst_table_free(mm, table); | 150 | crst_table_free(mm, table); |
| 147 | return; | 151 | goto out; |
| 148 | } | 152 | } |
| 149 | batch = rcu_table_freelist_get(mm); | 153 | batch = rcu_table_freelist_get(mm); |
| 150 | if (!batch) { | 154 | if (!batch) { |
| 151 | smp_call_function(smp_sync, NULL, 1); | 155 | smp_call_function(smp_sync, NULL, 1); |
| 152 | crst_table_free(mm, table); | 156 | crst_table_free(mm, table); |
| 153 | return; | 157 | goto out; |
| 154 | } | 158 | } |
| 155 | batch->table[--batch->crst_index] = table; | 159 | batch->table[--batch->crst_index] = table; |
| 156 | if (batch->pgt_index >= batch->crst_index) | 160 | if (batch->pgt_index >= batch->crst_index) |
| 157 | rcu_table_freelist_finish(); | 161 | rcu_table_freelist_finish(); |
| 162 | out: | ||
| 163 | preempt_enable(); | ||
| 158 | } | 164 | } |
| 159 | 165 | ||
| 160 | #ifdef CONFIG_64BIT | 166 | #ifdef CONFIG_64BIT |
| @@ -323,16 +329,17 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
| 323 | struct page *page; | 329 | struct page *page; |
| 324 | unsigned long bits; | 330 | unsigned long bits; |
| 325 | 331 | ||
| 332 | preempt_disable(); | ||
| 326 | if (atomic_read(&mm->mm_users) < 2 && | 333 | if (atomic_read(&mm->mm_users) < 2 && |
| 327 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 334 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
| 328 | page_table_free(mm, table); | 335 | page_table_free(mm, table); |
| 329 | return; | 336 | goto out; |
| 330 | } | 337 | } |
| 331 | batch = rcu_table_freelist_get(mm); | 338 | batch = rcu_table_freelist_get(mm); |
| 332 | if (!batch) { | 339 | if (!batch) { |
| 333 | smp_call_function(smp_sync, NULL, 1); | 340 | smp_call_function(smp_sync, NULL, 1); |
| 334 | page_table_free(mm, table); | 341 | page_table_free(mm, table); |
| 335 | return; | 342 | goto out; |
| 336 | } | 343 | } |
| 337 | bits = (mm->context.has_pgste) ? 3UL : 1UL; | 344 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
| 338 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 345 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
| @@ -345,6 +352,8 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
| 345 | batch->table[batch->pgt_index++] = table; | 352 | batch->table[batch->pgt_index++] = table; |
| 346 | if (batch->pgt_index >= batch->crst_index) | 353 | if (batch->pgt_index >= batch->crst_index) |
| 347 | rcu_table_freelist_finish(); | 354 | rcu_table_freelist_finish(); |
| 355 | out: | ||
| 356 | preempt_enable(); | ||
| 348 | } | 357 | } |
| 349 | 358 | ||
| 350 | /* | 359 | /* |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 79a6700b7162..6081493db68f 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
| @@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page) | |||
| 308 | { | 308 | { |
| 309 | #ifdef CONFIG_S390 | 309 | #ifdef CONFIG_S390 |
| 310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) | 310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) |
| 311 | page_set_storage_key(page_to_pfn(page), PAGE_DEFAULT_KEY, 0); | 311 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, 0); |
| 312 | #else | 312 | #else |
| 313 | /* | 313 | /* |
| 314 | * Memory barrier must be issued before setting the PG_uptodate bit, | 314 | * Memory barrier must be issued before setting the PG_uptodate bit, |
