diff options
author | Hauke Mehrtens <hauke@hauke-m.de> | 2014-06-08 22:52:39 +0200 |
---|---|---|
committer | Hauke Mehrtens <hauke@hauke-m.de> | 2014-06-16 20:23:38 +0200 |
commit | 5b0087cbb80eceadc1d4b05b587868abf0d9cf71 (patch) | |
tree | 19fd32c10509ee8a20ab167283a151eb4ad4ed2e /backport | |
parent | 85b9c4e29b11ef45cf81e1774b60a1b6e22efe2e (diff) |
backports: add split_page()
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Diffstat (limited to 'backport')
-rw-r--r-- | backport/compat/backport-3.10.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/backport/compat/backport-3.10.c b/backport/compat/backport-3.10.c index 9bcb8059..e75e52ed 100644 --- a/backport/compat/backport-3.10.c +++ b/backport/compat/backport-3.10.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/pci_regs.h> #include <linux/of.h> +#include <linux/mm.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) #include <linux/init.h> @@ -232,3 +233,48 @@ int of_property_read_u32_index(const struct device_node *np, } EXPORT_SYMBOL_GPL(of_property_read_u32_index); #endif /* CONFIG_OF */ + +static inline void set_page_count(struct page *page, int v) +{ + atomic_set(&page->_count, v); +} + +/* + * Turn a non-refcounted page (->_count == 0) into refcounted with + * a count of one. + */ +static inline void set_page_refcounted(struct page *page) +{ + VM_BUG_ON(PageTail(page)); + VM_BUG_ON(atomic_read(&page->_count)); + set_page_count(page, 1); +} + +/* + * split_page takes a non-compound higher-order page, and splits it into + * n (1<<order) sub-pages: page[0..n] + * Each sub-page must be freed individually. + * + * Note: this is probably too low level an operation for use in drivers. + * Please consult with lkml before using this in your driver. + */ +void split_page(struct page *page, unsigned int order) +{ + int i; + + VM_BUG_ON(PageCompound(page)); + VM_BUG_ON(!page_count(page)); + +#ifdef CONFIG_KMEMCHECK + /* + * Split shadow pages too, because free(page[0]) would + * otherwise free the whole shadow. + */ + if (kmemcheck_page_is_tracked(page)) + split_page(virt_to_page(page[0].shadow), order); +#endif + + for (i = 1; i < (1 << order); i++) + set_page_refcounted(page + i); +} +EXPORT_SYMBOL_GPL(split_page); |