|
@@ -581,10 +581,11 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
|
|
|
* sets it, so none of the operations on it need to be atomic.
|
|
|
*/
|
|
|
|
|
|
-/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
|
|
|
+/* Page flags: | [SECTION] | [NODE] | ZONE | [LAST_NID] | ... | FLAGS | */
|
|
|
#define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
|
|
|
#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH)
|
|
|
#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)
|
|
|
+#define LAST_NID_PGOFF (ZONES_PGOFF - LAST_NID_WIDTH)
|
|
|
|
|
|
/*
|
|
|
* Define the bit shifts to access each section. For non-existent
|
|
@@ -594,6 +595,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
|
|
|
#define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
|
|
|
#define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0))
|
|
|
#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0))
|
|
|
+#define LAST_NID_PGSHIFT (LAST_NID_PGOFF * (LAST_NID_WIDTH != 0))
|
|
|
|
|
|
/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */
|
|
|
#ifdef NODE_NOT_IN_PAGE_FLAGS
|
|
@@ -615,6 +617,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
|
|
|
#define ZONES_MASK ((1UL << ZONES_WIDTH) - 1)
|
|
|
#define NODES_MASK ((1UL << NODES_WIDTH) - 1)
|
|
|
#define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1)
|
|
|
+#define LAST_NID_MASK ((1UL << LAST_NID_WIDTH) - 1)
|
|
|
#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1)
|
|
|
|
|
|
static inline enum zone_type page_zonenum(const struct page *page)
|
|
@@ -654,6 +657,7 @@ static inline int page_to_nid(const struct page *page)
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_NUMA_BALANCING
|
|
|
+#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
|
|
|
static inline int page_xchg_last_nid(struct page *page, int nid)
|
|
|
{
|
|
|
return xchg(&page->_last_nid, nid);
|
|
@@ -668,6 +672,33 @@ static inline void reset_page_last_nid(struct page *page)
|
|
|
page->_last_nid = -1;
|
|
|
}
|
|
|
#else
|
|
|
+static inline int page_last_nid(struct page *page)
|
|
|
+{
|
|
|
+ return (page->flags >> LAST_NID_PGSHIFT) & LAST_NID_MASK;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int page_xchg_last_nid(struct page *page, int nid)
|
|
|
+{
|
|
|
+ unsigned long old_flags, flags;
|
|
|
+ int last_nid;
|
|
|
+
|
|
|
+ do {
|
|
|
+ old_flags = flags = page->flags;
|
|
|
+ last_nid = page_last_nid(page);
|
|
|
+
|
|
|
+ flags &= ~(LAST_NID_MASK << LAST_NID_PGSHIFT);
|
|
|
+ flags |= (nid & LAST_NID_MASK) << LAST_NID_PGSHIFT;
|
|
|
+ } while (unlikely(cmpxchg(&page->flags, old_flags, flags) != old_flags));
|
|
|
+
|
|
|
+ return last_nid;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void reset_page_last_nid(struct page *page)
|
|
|
+{
|
|
|
+ page_xchg_last_nid(page, (1 << LAST_NID_SHIFT) - 1);
|
|
|
+}
|
|
|
+#endif /* LAST_NID_NOT_IN_PAGE_FLAGS */
|
|
|
+#else
|
|
|
static inline int page_xchg_last_nid(struct page *page, int nid)
|
|
|
{
|
|
|
return page_to_nid(page);
|