diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-11-08 10:59:22 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:57 -0400 |
commit | 3ab2fb5a8cb003897016b6eb38ddad916226c1b2 (patch) | |
tree | dce5ac7ae586111c7e872193c09ced717b936549 | |
parent | 856bf3e592f917e7d663cb7fa93e83fe795e8f4e (diff) |
Btrfs: Add readpages support
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/extent_map.c | 70 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 12 |
3 files changed, 78 insertions, 8 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 754bc42c162a..0077c6c1d9f9 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/swap.h> | 11 | #include <linux/swap.h> |
12 | #include <linux/version.h> | 12 | #include <linux/version.h> |
13 | #include <linux/writeback.h> | 13 | #include <linux/writeback.h> |
14 | #include <linux/pagevec.h> | ||
14 | #include "extent_map.h" | 15 | #include "extent_map.h" |
15 | 16 | ||
16 | /* temporary define until extent_map moves out of btrfs */ | 17 | /* temporary define until extent_map moves out of btrfs */ |
@@ -1503,7 +1504,7 @@ static int submit_extent_page(int rw, struct extent_map_tree *tree, | |||
1503 | size_t size, unsigned long offset, | 1504 | size_t size, unsigned long offset, |
1504 | struct block_device *bdev, | 1505 | struct block_device *bdev, |
1505 | struct bio **bio_ret, | 1506 | struct bio **bio_ret, |
1506 | int max_pages, | 1507 | unsigned long max_pages, |
1507 | bio_end_io_t end_io_func) | 1508 | bio_end_io_t end_io_func) |
1508 | { | 1509 | { |
1509 | int ret = 0; | 1510 | int ret = 0; |
@@ -1520,7 +1521,7 @@ static int submit_extent_page(int rw, struct extent_map_tree *tree, | |||
1520 | return 0; | 1521 | return 0; |
1521 | } | 1522 | } |
1522 | } | 1523 | } |
1523 | nr = min(max_pages, bio_get_nr_vecs(bdev)); | 1524 | nr = min_t(int, max_pages, bio_get_nr_vecs(bdev)); |
1524 | bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); | 1525 | bio = extent_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH); |
1525 | if (!bio) { | 1526 | if (!bio) { |
1526 | printk("failed to allocate bio nr %d\n", nr); | 1527 | printk("failed to allocate bio nr %d\n", nr); |
@@ -1552,8 +1553,10 @@ void set_page_extent_mapped(struct page *page) | |||
1552 | * into the tree that are removed when the IO is done (by the end_io | 1553 | * into the tree that are removed when the IO is done (by the end_io |
1553 | * handlers) | 1554 | * handlers) |
1554 | */ | 1555 | */ |
1555 | int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | 1556 | static int __extent_read_full_page(struct extent_map_tree *tree, |
1556 | get_extent_t *get_extent) | 1557 | struct page *page, |
1558 | get_extent_t *get_extent, | ||
1559 | struct bio **bio) | ||
1557 | { | 1560 | { |
1558 | struct inode *inode = page->mapping->host; | 1561 | struct inode *inode = page->mapping->host; |
1559 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 1562 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
@@ -1631,10 +1634,12 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | |||
1631 | cur + iosize - 1); | 1634 | cur + iosize - 1); |
1632 | } | 1635 | } |
1633 | if (!ret) { | 1636 | if (!ret) { |
1637 | unsigned long nr = (last_byte >> PAGE_CACHE_SHIFT) + 1; | ||
1638 | nr -= page->index; | ||
1634 | ret = submit_extent_page(READ, tree, page, | 1639 | ret = submit_extent_page(READ, tree, page, |
1635 | sector, iosize, page_offset, | 1640 | sector, iosize, page_offset, |
1636 | bdev, NULL, 1, | 1641 | bdev, bio, nr, |
1637 | end_bio_extent_readpage); | 1642 | end_bio_extent_readpage); |
1638 | } | 1643 | } |
1639 | if (ret) | 1644 | if (ret) |
1640 | SetPageError(page); | 1645 | SetPageError(page); |
@@ -1649,6 +1654,18 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | |||
1649 | } | 1654 | } |
1650 | return 0; | 1655 | return 0; |
1651 | } | 1656 | } |
1657 | |||
1658 | int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | ||
1659 | get_extent_t *get_extent) | ||
1660 | { | ||
1661 | struct bio *bio = NULL; | ||
1662 | int ret; | ||
1663 | |||
1664 | ret = __extent_read_full_page(tree, page, get_extent, &bio); | ||
1665 | if (bio) | ||
1666 | submit_one_bio(READ, bio); | ||
1667 | return ret; | ||
1668 | } | ||
1652 | EXPORT_SYMBOL(extent_read_full_page); | 1669 | EXPORT_SYMBOL(extent_read_full_page); |
1653 | 1670 | ||
1654 | /* | 1671 | /* |
@@ -1836,6 +1853,45 @@ int extent_writepages(struct extent_map_tree *tree, | |||
1836 | } | 1853 | } |
1837 | EXPORT_SYMBOL(extent_writepages); | 1854 | EXPORT_SYMBOL(extent_writepages); |
1838 | 1855 | ||
1856 | int extent_readpages(struct extent_map_tree *tree, | ||
1857 | struct address_space *mapping, | ||
1858 | struct list_head *pages, unsigned nr_pages, | ||
1859 | get_extent_t get_extent) | ||
1860 | { | ||
1861 | struct bio *bio = NULL; | ||
1862 | unsigned page_idx; | ||
1863 | struct pagevec pvec; | ||
1864 | |||
1865 | pagevec_init(&pvec, 0); | ||
1866 | for (page_idx = 0; page_idx < nr_pages; page_idx++) { | ||
1867 | struct page *page = list_entry(pages->prev, struct page, lru); | ||
1868 | |||
1869 | prefetchw(&page->flags); | ||
1870 | list_del(&page->lru); | ||
1871 | /* | ||
1872 | * what we want to do here is call add_to_page_cache_lru, | ||
1873 | * but that isn't exported, so we reproduce it here | ||
1874 | */ | ||
1875 | if (!add_to_page_cache(page, mapping, | ||
1876 | page->index, GFP_KERNEL)) { | ||
1877 | |||
1878 | /* open coding of lru_cache_add, also not exported */ | ||
1879 | page_cache_get(page); | ||
1880 | if (!pagevec_add(&pvec, page)) | ||
1881 | __pagevec_lru_add(&pvec); | ||
1882 | __extent_read_full_page(tree, page, get_extent, &bio); | ||
1883 | } | ||
1884 | page_cache_release(page); | ||
1885 | } | ||
1886 | if (pagevec_count(&pvec)) | ||
1887 | __pagevec_lru_add(&pvec); | ||
1888 | BUG_ON(!list_empty(pages)); | ||
1889 | if (bio) | ||
1890 | submit_one_bio(READ, bio); | ||
1891 | return 0; | ||
1892 | } | ||
1893 | EXPORT_SYMBOL(extent_readpages); | ||
1894 | |||
1839 | /* | 1895 | /* |
1840 | * basic invalidatepage code, this waits on any locked or writeback | 1896 | * basic invalidatepage code, this waits on any locked or writeback |
1841 | * ranges corresponding to the page, and then deletes any extent state | 1897 | * ranges corresponding to the page, and then deletes any extent state |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 0b0dcf19fe45..fbd23a72f53b 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -140,6 +140,10 @@ int extent_writepages(struct extent_map_tree *tree, | |||
140 | struct address_space *mapping, | 140 | struct address_space *mapping, |
141 | get_extent_t *get_extent, | 141 | get_extent_t *get_extent, |
142 | struct writeback_control *wbc); | 142 | struct writeback_control *wbc); |
143 | int extent_readpages(struct extent_map_tree *tree, | ||
144 | struct address_space *mapping, | ||
145 | struct list_head *pages, unsigned nr_pages, | ||
146 | get_extent_t get_extent); | ||
143 | int extent_prepare_write(struct extent_map_tree *tree, | 147 | int extent_prepare_write(struct extent_map_tree *tree, |
144 | struct inode *inode, struct page *page, | 148 | struct inode *inode, struct page *page, |
145 | unsigned from, unsigned to, get_extent_t *get_extent); | 149 | unsigned from, unsigned to, get_extent_t *get_extent); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 90cb71d68294..d6d32465bc9a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1748,7 +1748,6 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc) | |||
1748 | return extent_write_full_page(tree, page, btrfs_get_extent, wbc); | 1748 | return extent_write_full_page(tree, page, btrfs_get_extent, wbc); |
1749 | } | 1749 | } |
1750 | 1750 | ||
1751 | |||
1752 | static int btrfs_writepages(struct address_space *mapping, | 1751 | static int btrfs_writepages(struct address_space *mapping, |
1753 | struct writeback_control *wbc) | 1752 | struct writeback_control *wbc) |
1754 | { | 1753 | { |
@@ -1757,6 +1756,16 @@ static int btrfs_writepages(struct address_space *mapping, | |||
1757 | return extent_writepages(tree, mapping, btrfs_get_extent, wbc); | 1756 | return extent_writepages(tree, mapping, btrfs_get_extent, wbc); |
1758 | } | 1757 | } |
1759 | 1758 | ||
1759 | static int | ||
1760 | btrfs_readpages(struct file *file, struct address_space *mapping, | ||
1761 | struct list_head *pages, unsigned nr_pages) | ||
1762 | { | ||
1763 | struct extent_map_tree *tree; | ||
1764 | tree = &BTRFS_I(mapping->host)->extent_tree; | ||
1765 | return extent_readpages(tree, mapping, pages, nr_pages, | ||
1766 | btrfs_get_extent); | ||
1767 | } | ||
1768 | |||
1760 | static int btrfs_releasepage(struct page *page, gfp_t unused_gfp_flags) | 1769 | static int btrfs_releasepage(struct page *page, gfp_t unused_gfp_flags) |
1761 | { | 1770 | { |
1762 | struct extent_map_tree *tree; | 1771 | struct extent_map_tree *tree; |
@@ -2537,6 +2546,7 @@ static struct address_space_operations btrfs_aops = { | |||
2537 | .readpage = btrfs_readpage, | 2546 | .readpage = btrfs_readpage, |
2538 | .writepage = btrfs_writepage, | 2547 | .writepage = btrfs_writepage, |
2539 | .writepages = btrfs_writepages, | 2548 | .writepages = btrfs_writepages, |
2549 | .readpages = btrfs_readpages, | ||
2540 | .sync_page = block_sync_page, | 2550 | .sync_page = block_sync_page, |
2541 | .prepare_write = btrfs_prepare_write, | 2551 | .prepare_write = btrfs_prepare_write, |
2542 | .commit_write = btrfs_commit_write, | 2552 | .commit_write = btrfs_commit_write, |