aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2011-05-29 06:40:50 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2011-05-29 06:40:51 -0400
commita43a9d93d40a69eceeb4e4a4c860cc20186d475c (patch)
tree36eaef08f89d835091344c2d294926314833024e /arch/s390
parent139f37f5e14cd883eee2a8a36289f544b5390a44 (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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/pgtable.h16
1 files changed, 8 insertions, 8 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)
577static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) 577static 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)
628static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) 628static 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