[S390] merge page_test_dirty and page_clear_dirty
The page_clear_dirty primitive always sets the default storage key which resets the access control bits and the fetch protection bit. That will surprise a KVM guest that sets non-zero access control bits or the fetch protection bit. Merge page_test_dirty and page_clear_dirty back to a single function and only clear the dirty bit from the storage key. In addition move the function page_test_and_clear_dirty and page_test_and_clear_young to page.h where they belong. This requires to change the parameter from a struct page * to a page frame number. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
@@ -107,8 +107,8 @@ typedef pte_t *pgtable_t;
|
||||
#define __pgd(x) ((pgd_t) { (x) } )
|
||||
#define __pgprot(x) ((pgprot_t) { (x) } )
|
||||
|
||||
static inline void
|
||||
page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
|
||||
static inline void page_set_storage_key(unsigned long addr,
|
||||
unsigned char skey, int mapped)
|
||||
{
|
||||
if (!mapped)
|
||||
asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
|
||||
@@ -117,15 +117,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
|
||||
asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
page_get_storage_key(unsigned long addr)
|
||||
static inline unsigned char page_get_storage_key(unsigned long addr)
|
||||
{
|
||||
unsigned int skey;
|
||||
unsigned char skey;
|
||||
|
||||
asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
|
||||
asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr));
|
||||
return skey;
|
||||
}
|
||||
|
||||
static inline int page_reset_referenced(unsigned long addr)
|
||||
{
|
||||
unsigned int ipm;
|
||||
|
||||
asm volatile(
|
||||
" rrbe 0,%1\n"
|
||||
" ipm %0\n"
|
||||
: "=d" (ipm) : "a" (addr) : "cc");
|
||||
return !!(ipm & 0x20000000);
|
||||
}
|
||||
|
||||
/* Bits int the storage key */
|
||||
#define _PAGE_CHANGED 0x02 /* HW changed bit */
|
||||
#define _PAGE_REFERENCED 0x04 /* HW referenced bit */
|
||||
#define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */
|
||||
#define _PAGE_ACC_BITS 0xf0 /* HW access control bits */
|
||||
|
||||
/*
|
||||
* Test and clear dirty bit in storage key.
|
||||
* We can't clear the changed bit atomically. This is a potential
|
||||
* race against modification of the referenced bit. This function
|
||||
* should therefore only be called if it is not mapped in any
|
||||
* address space.
|
||||
*/
|
||||
#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
|
||||
static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped)
|
||||
{
|
||||
unsigned char skey;
|
||||
|
||||
skey = page_get_storage_key(pfn << PAGE_SHIFT);
|
||||
if (!(skey & _PAGE_CHANGED))
|
||||
return 0;
|
||||
page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test and clear referenced bit in storage key.
|
||||
*/
|
||||
#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
|
||||
static inline int page_test_and_clear_young(unsigned long pfn)
|
||||
{
|
||||
return page_reset_referenced(pfn << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
struct page;
|
||||
void arch_free_page(struct page *page, int order);
|
||||
void arch_alloc_page(struct page *page, int order);
|
||||
|
Reference in New Issue
Block a user