[RFC][PATCH] page->mapping clarification [1/3] base functions

From: KAMEZAWA Hiroyuki
Date: Wed Sep 19 2007 - 03:41:36 EST


Rebased to 2.6.23-rc6-mm1 and reflected comments.
Not so aggresive as previous version.
(I'm not in a hurry if -mm is busy.)

Any comments are welcome.

Thanks,
-Kame
==
A clarification of page <-> fs interface (page cache).

At first, each FS has to access to struct page->mapping directly.
But it's not just pointer. (we use special 1bit enconding for anon.)

Although there is historical consensus that page->mapping points to its inode's
address space, I think adding some neat helper functon is not bad.

This patch adds page-cache.h which containes page<->address_space<->inode
function which is required (used) by subsystems.

Following functions are added

* page_mapping_cache() ... returns address space if a page is page cache
* page_mapping_anon() ... returns anon_vma if a page is anonymous page.
* page_is_pagecache() ... returns true if a page is page-cache.
* page_inode() ... returns inode which a page-cache belongs to.
* is_page_consistent() ... returns true if a page is still valid page cache

Followings are moved
* page_mapping() ... returns swapper_space or address_space a page is on.
(from mm.h)
* page_index() ... returns position of a page in its inode
(from mm.h)
* remove_mapping() ... a safe routine to remove page->mapping from page.
(from swap.h)

Changelog V1 -> V2:
- for 2.6.23-rc6-mm1.
- use bool type.
- moved related functions to page-cache.h
- renamed some functions.

Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx>

---
include/linux/fs.h | 6 +-
include/linux/mm.h | 40 ---------------
include/linux/page-cache.h | 118 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/swap.h | 1
4 files changed, 123 insertions(+), 42 deletions(-)

Index: linux-2.6.23-rc6-mm1/include/linux/page-cache.h
===================================================================
--- /dev/null
+++ linux-2.6.23-rc6-mm1/include/linux/page-cache.h
@@ -0,0 +1,118 @@
+#ifndef _LINUX_PAGE_CACHE_H
+#define _LINUX_PAGE_CACHE_H
+#ifdef __KERNEL__
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/rmap.h>
+/*
+ * This file defines interface function among page-cache and FS.
+ *
+ * page_mapping() ... returns swapper_space or address_space a page is on.
+ * Will be used by routines walks by LRU.
+ * page_mapping_cache() ... returns address space if a page is page cache
+ * Will be used by FS.
+ * page_mapping_anon() ... returns anon_vma if a page is anonymous page.
+ * Will be used by VM subsystem
+ * page_is_pagecache() ... returns true if a page is page-cache.
+ * page_inode() ... returns inode which a page-cache belongs to.
+ * page_index() ... returns position of a page in its inode
+ * is_page_consistent() ... returns true if a page is still valid on specified
+ * address space.
+ * remove_mapping() ... a safe routine to remove page->mapping from page.
+ */
+extern struct address_space swapper_space;
+
+/*
+ * On an anonymous page mapped into a user virtual memory area,
+ * page->mapping points to its anon_vma, not to a struct address_space;
+ * with the PAGE_MAPPING_ANON bit set to distinguish it.
+ *
+ * Please note that, confusingly, "page_mapping" refers to the inode
+ * address_space which maps the page from disk; whereas "page_mapped"
+ * refers to user virtual address space into which the page is mapped.
+ */
+#define PAGE_MAPPING_ANON 1
+
+static inline bool PageAnon(struct page *page)
+{
+ return (((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0);
+}
+
+static inline struct anon_vma *page_mapping_anon(struct page *page)
+{
+ if (!page->mapping || !PageAnon(page))
+ return NULL;
+ return (struct anon_vma *)
+ ((unsigned long)page->mapping - PAGE_MAPPING_ANON);
+}
+
+static inline struct address_space *page_mapping_cache(struct page *page)
+{
+ if (!page->mapping || PageAnon(page))
+ return NULL;
+ return page->mapping;
+}
+
+/*
+ * Automatically detect 'what the page is' and returns address_space.
+ *
+ * If page is swap cache, returns &swapper_space.
+ * If page is page cache, returns inode's address space it belongs to
+ * If page is anon, returns NULL.
+ */
+
+static inline struct address_space *page_mapping(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+
+ VM_BUG_ON(PageSlab(page));
+ if (unlikely(PageSwapCache(page)))
+ mapping = &swapper_space;
+#ifdef CONFIG_SLUB
+ else if (unlikely(PageSlab(page)))
+ mapping = NULL;
+#endif
+ else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
+ mapping = NULL;
+ return mapping;
+
+}
+
+static inline bool page_is_pagecache(struct page *page)
+{
+ return (page_mapping_cache(page) != NULL);
+}
+
+static inline struct inode *page_inode(struct page *page)
+{
+ if (!page_is_pagecache(page))
+ return NULL;
+ return page_mapping_cache(page)->host;
+}
+/*
+ * Return the pagecache index of the passed page. Regular pagecache pages
+ * use ->index whereas swapcache pages use ->private
+ */
+static inline pgoff_t page_index(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return page_private(page);
+ return page->index;
+}
+
+/*
+ * Returns true if a page is belongs to mapping.
+ */
+static inline bool
+is_page_consistent(struct page *page, struct address_space *mapping)
+{
+ struct address_space *check = page_mapping_cache(page);
+ return (check == mapping);
+}
+
+/* defined in mm/vmscan.c. Must be called under lock_page(). */
+extern int remove_mapping(struct address_space *mapping, struct page *page);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_PAGE_CACHE_H */
Index: linux-2.6.23-rc6-mm1/include/linux/mm.h
===================================================================
--- linux-2.6.23-rc6-mm1.orig/include/linux/mm.h
+++ linux-2.6.23-rc6-mm1/include/linux/mm.h
@@ -550,46 +550,6 @@ void page_address_init(void);
#endif

/*
- * On an anonymous page mapped into a user virtual memory area,
- * page->mapping points to its anon_vma, not to a struct address_space;
- * with the PAGE_MAPPING_ANON bit set to distinguish it.
- *
- * Please note that, confusingly, "page_mapping" refers to the inode
- * address_space which maps the page from disk; whereas "page_mapped"
- * refers to user virtual address space into which the page is mapped.
- */
-#define PAGE_MAPPING_ANON 1
-
-extern struct address_space swapper_space;
-static inline struct address_space *page_mapping(struct page *page)
-{
- struct address_space *mapping = page->mapping;
-
- VM_BUG_ON(PageSlab(page));
- if (unlikely(PageSwapCache(page)))
- mapping = &swapper_space;
- else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
- mapping = NULL;
- return mapping;
-}
-
-static inline int PageAnon(struct page *page)
-{
- return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
-}
-
-/*
- * Return the pagecache index of the passed page. Regular pagecache pages
- * use ->index whereas swapcache pages use ->private
- */
-static inline pgoff_t page_index(struct page *page)
-{
- if (unlikely(PageSwapCache(page)))
- return page_private(page);
- return page->index;
-}
-
-/*
* The atomic page->_mapcount, like _count, starts from -1:
* so that transitions both from it and to it can be tracked,
* using atomic_inc_and_test and atomic_add_negative(-1).
Index: linux-2.6.23-rc6-mm1/include/linux/fs.h
===================================================================
--- linux-2.6.23-rc6-mm1.orig/include/linux/fs.h
+++ linux-2.6.23-rc6-mm1/include/linux/fs.h
@@ -517,12 +517,16 @@ struct address_space {
struct list_head private_list; /* ditto */
struct address_space *assoc_mapping; /* ditto */
} __attribute__((aligned(sizeof(long))));
+
+
+#include <linux/page-cache.h>
+
+
/*
* On most architectures that alignment is already the case; but
* must be enforced here for CRIS, to let the least signficant bit
* of struct page's "mapping" pointer be used for PAGE_MAPPING_ANON.
*/
-
struct block_device {
dev_t bd_dev; /* not a kdev_t - it's a search key */
struct inode * bd_inode; /* will die */
Index: linux-2.6.23-rc6-mm1/include/linux/swap.h
===================================================================
--- linux-2.6.23-rc6-mm1.orig/include/linux/swap.h
+++ linux-2.6.23-rc6-mm1/include/linux/swap.h
@@ -196,7 +196,6 @@ extern unsigned long try_to_free_mem_con
extern int __isolate_lru_page(struct page *page, int mode);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
-extern int remove_mapping(struct address_space *mapping, struct page *page);
extern long vm_total_pages;

#ifdef CONFIG_NUMA

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/