aboutsummaryrefslogtreecommitdiffstats
path: root/fs/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 1a80b04..c780e39 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -38,6 +38,7 @@
#include <linux/bio.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
+#include <linux/smp.h>
#include <linux/bitops.h>
#include <linux/mpage.h>
#include <linux/bit_spinlock.h>
@@ -996,8 +997,13 @@ grow_dev_page(struct block_device *bdev, sector_t block,
struct page *page;
struct buffer_head *bh;
+#ifdef CONFIG_DMA_CMA
+ page = find_or_create_page(inode->i_mapping, index,
+ (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS));
+#else
page = find_or_create_page(inode->i_mapping, index,
(mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
+#endif
if (!page)
return NULL;
@@ -1270,6 +1276,16 @@ static void bh_lru_install(struct buffer_head *bh)
{
struct buffer_head *evictee = NULL;
+#ifdef CONFIG_DMA_CMA
+ /*
+ * Pages are busy when their buffers stay on bh_lru list.
+ * The CMA pages are expected to be migrated at any time,
+ * therefore they should never go on any local LRU lists.
+ */
+ if (is_cma_pageblock(bh->b_page))
+ return;
+#endif
+
check_irqs_on();
bh_lru_lock();
if (__this_cpu_read(bh_lrus.bhs[0]) != bh) {
@@ -1438,6 +1454,35 @@ void invalidate_bh_lrus(void)
}
EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
+#ifdef CONFIG_DMA_CMA
+static void evict_bh_lru(void *arg)
+{
+ struct bh_lru *b = &get_cpu_var(bh_lrus);
+ struct buffer_head *bh = arg;
+ int i;
+
+ for (i = 0; i < BH_LRU_SIZE; i++) {
+ if (b->bhs[i] == bh) {
+ printk(KERN_INFO "%s[%d] drop buffer head %p.\n",
+ __func__, __LINE__, b->bhs[i]);
+ brelse(b->bhs[i]);
+ b->bhs[i] = NULL;
+ break;
+ }
+ }
+
+ put_cpu_var(bh_lrus);
+}
+
+void evict_bh_lrus(struct buffer_head *bh)
+{
+ on_each_cpu(evict_bh_lru, bh, 1);
+}
+#else
+static inline void evict_bh_lrus(struct buffer_head *bh) {}
+#endif
+EXPORT_SYMBOL_GPL(evict_bh_lrus);
+
void set_bh_page(struct buffer_head *bh,
struct page *page, unsigned long offset)
{
@@ -3085,6 +3130,7 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = head;
do {
+ evict_bh_lrus(bh);
if (buffer_write_io_error(bh) && page->mapping)
set_bit(AS_EIO, &page->mapping->flags);
if (buffer_busy(bh))