backports: add split_page()
authorHauke Mehrtens <hauke@hauke-m.de>
Sun, 8 Jun 2014 20:52:39 +0000 (22:52 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Mon, 16 Jun 2014 18:23:38 +0000 (20:23 +0200)
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
backport/compat/backport-3.10.c

index 9bcb8059506a69b43a33897c3e29594a20144ab6..e75e52ed8164721ac6a31f68b93ead6ef4df42df 100644 (file)
@@ -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);