[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>
	
	
This commit is contained in:
		
					parent
					
						
							
								139f37f5e1
							
						
					
				
			
			
				commit
				
					
						a43a9d93d4
					
				
			
		
					 2 changed files with 9 additions and 9 deletions
				
			
		| 
						 | 
					@ -577,16 +577,16 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
 | 
				
			||||||
static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
 | 
					static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_PGSTE
 | 
					#ifdef CONFIG_PGSTE
 | 
				
			||||||
	unsigned long pfn, bits;
 | 
						unsigned long address, bits;
 | 
				
			||||||
	unsigned char skey;
 | 
						unsigned char skey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pfn = pte_val(*ptep) >> PAGE_SHIFT;
 | 
						address = pte_val(*ptep) & PAGE_MASK;
 | 
				
			||||||
	skey = page_get_storage_key(pfn);
 | 
						skey = page_get_storage_key(address);
 | 
				
			||||||
	bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
 | 
						bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
 | 
				
			||||||
	/* Clear page changed & referenced bit in the storage key */
 | 
						/* Clear page changed & referenced bit in the storage key */
 | 
				
			||||||
	if (bits) {
 | 
						if (bits) {
 | 
				
			||||||
		skey ^= bits;
 | 
							skey ^= bits;
 | 
				
			||||||
		page_set_storage_key(pfn, skey, 1);
 | 
							page_set_storage_key(address, skey, 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Transfer page changed & referenced bit to guest bits in pgste */
 | 
						/* Transfer page changed & referenced bit to guest bits in pgste */
 | 
				
			||||||
	pgste_val(pgste) |= bits << 48;		/* RCP_GR_BIT & RCP_GC_BIT */
 | 
						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)
 | 
				
			||||||
static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
 | 
					static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_PGSTE
 | 
					#ifdef CONFIG_PGSTE
 | 
				
			||||||
	unsigned long pfn;
 | 
						unsigned long address;
 | 
				
			||||||
	unsigned long okey, nkey;
 | 
						unsigned long okey, nkey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pfn = pte_val(*ptep) >> PAGE_SHIFT;
 | 
						address = pte_val(*ptep) & PAGE_MASK;
 | 
				
			||||||
	okey = nkey = page_get_storage_key(pfn);
 | 
						okey = nkey = page_get_storage_key(address);
 | 
				
			||||||
	nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
 | 
						nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
 | 
				
			||||||
	/* Set page access key and fetch protection bit from pgste */
 | 
						/* Set page access key and fetch protection bit from pgste */
 | 
				
			||||||
	nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
 | 
						nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
 | 
				
			||||||
	if (okey != nkey)
 | 
						if (okey != nkey)
 | 
				
			||||||
		page_set_storage_key(pfn, nkey, 1);
 | 
							page_set_storage_key(address, nkey, 1);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_S390
 | 
					#ifdef CONFIG_S390
 | 
				
			||||||
	if (!test_and_set_bit(PG_uptodate, &page->flags))
 | 
						if (!test_and_set_bit(PG_uptodate, &page->flags))
 | 
				
			||||||
		page_set_storage_key(page_to_pfn(page), PAGE_DEFAULT_KEY, 0);
 | 
							page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, 0);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Memory barrier must be issued before setting the PG_uptodate bit,
 | 
						 * Memory barrier must be issued before setting the PG_uptodate bit,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue