diff options
| author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-29 06:40:50 -0400 |
|---|---|---|
| committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-29 06:40:51 -0400 |
| commit | a43a9d93d40a69eceeb4e4a4c860cc20186d475c (patch) | |
| tree | 36eaef08f89d835091344c2d294926314833024e | |
| parent | 139f37f5e14cd883eee2a8a36289f544b5390a44 (diff) | |
[S390] mm: fix storage key handling
page_get_storage_key() and page_set_storage_key() expect a page address
and not its page frame number. This got inconsistent with 2d42552d
"[S390] merge page_test_dirty and page_clear_dirty".
Result is that we read/write storage keys from random pages and do not
have a working dirty bit tracking at all.
E.g. SetPageUpdate() doesn't clear the dirty bit of requested pages, which
for example ext4 doesn't like very much and panics after a while.
Unable to handle kernel paging request at virtual user address (null)
Oops: 0004 [#1] PREEMPT SMP DEBUG_PAGEALLOC
Modules linked in:
CPU: 1 Not tainted 2.6.39-07551-g139f37f-dirty #152
Process flush-94:0 (pid: 1576, task: 000000003eb34538, ksp: 000000003c287b70)
Krnl PSW : 0704c00180000000 0000000000316b12 (jbd2_journal_file_inode+0x10e/0x138)
R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 EA:3
Krnl GPRS: 0000000000000000 0000000000000000 0000000000000000 0700000000000000
0000000000316a62 000000003eb34cd0 0000000000000025 000000003c287b88
0000000000000001 000000003c287a70 000000003f1ec678 000000003f1ec000
0000000000000000 000000003e66ec00 0000000000316a62 000000003c287988
Krnl Code: 0000000000316b04: f0a0000407f4 srp 4(11,%r0),2036,0
0000000000316b0a: b9020022 ltgr %r2,%r2
0000000000316b0e: a7740015 brc 7,316b38
>0000000000316b12: e3d0c0000024 stg %r13,0(%r12)
0000000000316b18: 4120c010 la %r2,16(%r12)
0000000000316b1c: 4130d060 la %r3,96(%r13)
0000000000316b20: e340d0600004 lg %r4,96(%r13)
0000000000316b26: c0e50002b567 brasl %r14,36d5f4
Call Trace:
([<0000000000316a62>] jbd2_journal_file_inode+0x5e/0x138)
[<00000000002da13c>] mpage_da_map_and_submit+0x2e8/0x42c
[<00000000002daac2>] ext4_da_writepages+0x2da/0x504
[<00000000002597e8>] writeback_single_inode+0xf8/0x268
[<0000000000259f06>] writeback_sb_inodes+0xd2/0x18c
[<000000000025a700>] writeback_inodes_wb+0x80/0x168
[<000000000025aa92>] wb_writeback+0x2aa/0x324
[<000000000025abde>] wb_do_writeback+0xd2/0x274
[<000000000025ae3a>] bdi_writeback_thread+0xba/0x1c4
[<00000000001737be>] kthread+0xa6/0xb0
[<000000000056c1da>] kernel_thread_starter+0x6/0xc
[<000000000056c1d4>] kernel_thread_starter+0x0/0xc
INFO: lockdep is turned off.
Last Breaking-Event-Address:
[<0000000000316a8a>] jbd2_journal_file_inode+0x86/0x138
Reported-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 16 | ||||
| -rw-r--r-- | include/linux/page-flags.h | 2 |
2 files changed, 9 insertions, 9 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/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, |
