diff options
Diffstat (limited to 'fs/buffer.c')
-rw-r--r-- | fs/buffer.c | 46 |
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)) |