patch-2.4.13 linux/include/asm-s390/pgtable.h

Next file: linux/include/asm-s390/ptrace.h
Previous file: linux/include/asm-s390/pgalloc.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.12/linux/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
@@ -58,13 +58,6 @@
 #endif /* !__ASSEMBLY__ */
 
 /*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-/*
  * PMD_SHIFT determines the size of the area a second-level page
  * table can map
  */
@@ -162,6 +155,7 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
+#define _PAGE_MKCLEAR   0x002          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -226,6 +220,25 @@
 #define __S111  PAGE_SHARED
 
 /*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
+	    == _PAGE_MKCLEAR) 
+	{
+		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+               
+		asm volatile ("sske %0,%1" 
+				: : "d" (0), "a" (pte_val(pteval)));
+	}
+
+	*pteptr = pteval;
+}
+
+/*
  * Permanent address of a page.
  */
 #define page_address(page) ((page)->virtual)
@@ -323,23 +336,22 @@
 
 extern inline pte_t pte_mkclean(pte_t pte)
 {
-	/* We can't clear the changed bit atomically. The iske/and/sske
-         * sequence has a race condition with the page referenced bit.
-         * At the moment pte_mkclean is always followed by a pte_mkold.
-         * So its safe to ignore the problem for now. Hope this will
-         * never change ... */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (0), "a" (pte_val(pte)));
+	/* The only user of pte_mkclean is the fork() code.
+	   We must *not* clear the *physical* page dirty bit
+	   just because fork() wants to clear the dirty bit in
+	   *one* of the page's mappings.  So we just do nothing. */
 	return pte;
 }
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 {
-	/* We can't set the changed bit atomically either. For now we
+	/* We can't set the changed bit atomically. For now we
          * set (!) the page referenced bit. */
 	asm volatile ("sske %0,%1" 
 	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
 		          "a" (pte_val(pte)));
+
+	pte_val(pte) &= ~_PAGE_MKCLEAR;
 	return pte;
 }
 
@@ -411,7 +423,23 @@
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
 	return __pte;
 }
-#define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot)
+
+#define mk_pte(pg, pgprot)                                                \
+({                                                                        \
+	struct page *__page = (pg);                                       \
+	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
+	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
+	                                                                  \
+	if (__page != ZERO_PAGE(__physpage)) {                            \
+		int __users = page_count(__page);                         \
+		__users -= !!__page->buffers + !!__page->mapping;         \
+	                                                                  \
+		if (__users == 1)                                         \
+			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
+        }                                                                 \
+	                                                                  \
+	__pte;                                                            \
+})
 
 #define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 
@@ -472,6 +500,11 @@
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define PageSkip(page)          (0)
 #define kern_addr_valid(addr)   (1)
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
 
 #endif /* _S390_PAGE_H */
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)