diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-04-03 23:53:28 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-05-10 09:21:44 -0400 |
commit | 1cb2d38cb3e59d58e8321a0592e84b5761afb063 (patch) | |
tree | 151e7ffccd72f786a3da511b0f23906961835a22 /fs/nilfs2/segment.c | |
parent | eaae0f37d83bed7ccd0c6d0f52de1de44f92aecc (diff) |
nilfs2: get rid of private page allocator
Previously, nilfs was cloning pages for mmapped region to freeze their
data and ensure consistency of checksum during writeback cycles. A
private page allocator was used for this page cloning. But, we no
longer need to do that since clear_page_dirty_for_io function sets up
pte so that vm_ops->page_mkwrite function is called right before the
mmapped pages are modified and nilfs_page_mkwrite function can safely
wait for the pages to be written back to disk.
So, this stops making a copy of mmapped pages during writeback, and
eliminates the private page allocation and deallocation functions from
nilfs.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/segment.c')
-rw-r--r-- | fs/nilfs2/segment.c | 153 |
1 files changed, 17 insertions, 136 deletions
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 5deeadda9083..abbfab974700 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -1556,83 +1556,24 @@ static int nilfs_segctor_assign(struct nilfs_sc_info *sci, int mode) | |||
1556 | return 0; | 1556 | return 0; |
1557 | } | 1557 | } |
1558 | 1558 | ||
1559 | static int | 1559 | static void nilfs_begin_page_io(struct page *page) |
1560 | nilfs_copy_replace_page_buffers(struct page *page, struct list_head *out) | ||
1561 | { | ||
1562 | struct page *clone_page; | ||
1563 | struct buffer_head *bh, *head, *bh2; | ||
1564 | void *kaddr; | ||
1565 | |||
1566 | bh = head = page_buffers(page); | ||
1567 | |||
1568 | clone_page = nilfs_alloc_private_page(bh->b_bdev, bh->b_size, 0); | ||
1569 | if (unlikely(!clone_page)) | ||
1570 | return -ENOMEM; | ||
1571 | |||
1572 | bh2 = page_buffers(clone_page); | ||
1573 | kaddr = kmap_atomic(page, KM_USER0); | ||
1574 | do { | ||
1575 | if (list_empty(&bh->b_assoc_buffers)) | ||
1576 | continue; | ||
1577 | get_bh(bh2); | ||
1578 | page_cache_get(clone_page); /* for each bh */ | ||
1579 | memcpy(bh2->b_data, kaddr + bh_offset(bh), bh2->b_size); | ||
1580 | bh2->b_blocknr = bh->b_blocknr; | ||
1581 | list_replace(&bh->b_assoc_buffers, &bh2->b_assoc_buffers); | ||
1582 | list_add_tail(&bh->b_assoc_buffers, out); | ||
1583 | } while (bh = bh->b_this_page, bh2 = bh2->b_this_page, bh != head); | ||
1584 | kunmap_atomic(kaddr, KM_USER0); | ||
1585 | |||
1586 | if (!TestSetPageWriteback(clone_page)) | ||
1587 | account_page_writeback(clone_page); | ||
1588 | unlock_page(clone_page); | ||
1589 | |||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | static int nilfs_test_page_to_be_frozen(struct page *page) | ||
1594 | { | ||
1595 | struct address_space *mapping = page->mapping; | ||
1596 | |||
1597 | if (!mapping || !mapping->host || S_ISDIR(mapping->host->i_mode)) | ||
1598 | return 0; | ||
1599 | |||
1600 | if (page_mapped(page)) { | ||
1601 | ClearPageChecked(page); | ||
1602 | return 1; | ||
1603 | } | ||
1604 | return PageChecked(page); | ||
1605 | } | ||
1606 | |||
1607 | static int nilfs_begin_page_io(struct page *page, struct list_head *out) | ||
1608 | { | 1560 | { |
1609 | if (!page || PageWriteback(page)) | 1561 | if (!page || PageWriteback(page)) |
1610 | /* For split b-tree node pages, this function may be called | 1562 | /* For split b-tree node pages, this function may be called |
1611 | twice. We ignore the 2nd or later calls by this check. */ | 1563 | twice. We ignore the 2nd or later calls by this check. */ |
1612 | return 0; | 1564 | return; |
1613 | 1565 | ||
1614 | lock_page(page); | 1566 | lock_page(page); |
1615 | clear_page_dirty_for_io(page); | 1567 | clear_page_dirty_for_io(page); |
1616 | set_page_writeback(page); | 1568 | set_page_writeback(page); |
1617 | unlock_page(page); | 1569 | unlock_page(page); |
1618 | |||
1619 | if (nilfs_test_page_to_be_frozen(page)) { | ||
1620 | int err = nilfs_copy_replace_page_buffers(page, out); | ||
1621 | if (unlikely(err)) | ||
1622 | return err; | ||
1623 | } | ||
1624 | return 0; | ||
1625 | } | 1570 | } |
1626 | 1571 | ||
1627 | static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci, | 1572 | static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci) |
1628 | struct page **failed_page) | ||
1629 | { | 1573 | { |
1630 | struct nilfs_segment_buffer *segbuf; | 1574 | struct nilfs_segment_buffer *segbuf; |
1631 | struct page *bd_page = NULL, *fs_page = NULL; | 1575 | struct page *bd_page = NULL, *fs_page = NULL; |
1632 | struct list_head *list = &sci->sc_copied_buffers; | ||
1633 | int err; | ||
1634 | 1576 | ||
1635 | *failed_page = NULL; | ||
1636 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { | 1577 | list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) { |
1637 | struct buffer_head *bh; | 1578 | struct buffer_head *bh; |
1638 | 1579 | ||
@@ -1662,11 +1603,7 @@ static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci, | |||
1662 | break; | 1603 | break; |
1663 | } | 1604 | } |
1664 | if (bh->b_page != fs_page) { | 1605 | if (bh->b_page != fs_page) { |
1665 | err = nilfs_begin_page_io(fs_page, list); | 1606 | nilfs_begin_page_io(fs_page); |
1666 | if (unlikely(err)) { | ||
1667 | *failed_page = fs_page; | ||
1668 | goto out; | ||
1669 | } | ||
1670 | fs_page = bh->b_page; | 1607 | fs_page = bh->b_page; |
1671 | } | 1608 | } |
1672 | } | 1609 | } |
@@ -1677,11 +1614,7 @@ static int nilfs_segctor_prepare_write(struct nilfs_sc_info *sci, | |||
1677 | set_page_writeback(bd_page); | 1614 | set_page_writeback(bd_page); |
1678 | unlock_page(bd_page); | 1615 | unlock_page(bd_page); |
1679 | } | 1616 | } |
1680 | err = nilfs_begin_page_io(fs_page, list); | 1617 | nilfs_begin_page_io(fs_page); |
1681 | if (unlikely(err)) | ||
1682 | *failed_page = fs_page; | ||
1683 | out: | ||
1684 | return err; | ||
1685 | } | 1618 | } |
1686 | 1619 | ||
1687 | static int nilfs_segctor_write(struct nilfs_sc_info *sci, | 1620 | static int nilfs_segctor_write(struct nilfs_sc_info *sci, |
@@ -1694,24 +1627,6 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci, | |||
1694 | return ret; | 1627 | return ret; |
1695 | } | 1628 | } |
1696 | 1629 | ||
1697 | static void __nilfs_end_page_io(struct page *page, int err) | ||
1698 | { | ||
1699 | if (!err) { | ||
1700 | if (!nilfs_page_buffers_clean(page)) | ||
1701 | __set_page_dirty_nobuffers(page); | ||
1702 | ClearPageError(page); | ||
1703 | } else { | ||
1704 | __set_page_dirty_nobuffers(page); | ||
1705 | SetPageError(page); | ||
1706 | } | ||
1707 | |||
1708 | if (buffer_nilfs_allocated(page_buffers(page))) { | ||
1709 | if (TestClearPageWriteback(page)) | ||
1710 | dec_zone_page_state(page, NR_WRITEBACK); | ||
1711 | } else | ||
1712 | end_page_writeback(page); | ||
1713 | } | ||
1714 | |||
1715 | static void nilfs_end_page_io(struct page *page, int err) | 1630 | static void nilfs_end_page_io(struct page *page, int err) |
1716 | { | 1631 | { |
1717 | if (!page) | 1632 | if (!page) |
@@ -1738,40 +1653,19 @@ static void nilfs_end_page_io(struct page *page, int err) | |||
1738 | return; | 1653 | return; |
1739 | } | 1654 | } |
1740 | 1655 | ||
1741 | __nilfs_end_page_io(page, err); | 1656 | if (!err) { |
1742 | } | 1657 | if (!nilfs_page_buffers_clean(page)) |
1743 | 1658 | __set_page_dirty_nobuffers(page); | |
1744 | static void nilfs_clear_copied_buffers(struct list_head *list, int err) | 1659 | ClearPageError(page); |
1745 | { | 1660 | } else { |
1746 | struct buffer_head *bh, *head; | 1661 | __set_page_dirty_nobuffers(page); |
1747 | struct page *page; | 1662 | SetPageError(page); |
1748 | |||
1749 | while (!list_empty(list)) { | ||
1750 | bh = list_entry(list->next, struct buffer_head, | ||
1751 | b_assoc_buffers); | ||
1752 | page = bh->b_page; | ||
1753 | page_cache_get(page); | ||
1754 | head = bh = page_buffers(page); | ||
1755 | do { | ||
1756 | if (!list_empty(&bh->b_assoc_buffers)) { | ||
1757 | list_del_init(&bh->b_assoc_buffers); | ||
1758 | if (!err) { | ||
1759 | set_buffer_uptodate(bh); | ||
1760 | clear_buffer_dirty(bh); | ||
1761 | clear_buffer_delay(bh); | ||
1762 | clear_buffer_nilfs_volatile(bh); | ||
1763 | } | ||
1764 | brelse(bh); /* for b_assoc_buffers */ | ||
1765 | } | ||
1766 | } while ((bh = bh->b_this_page) != head); | ||
1767 | |||
1768 | __nilfs_end_page_io(page, err); | ||
1769 | page_cache_release(page); | ||
1770 | } | 1663 | } |
1664 | |||
1665 | end_page_writeback(page); | ||
1771 | } | 1666 | } |
1772 | 1667 | ||
1773 | static void nilfs_abort_logs(struct list_head *logs, struct page *failed_page, | 1668 | static void nilfs_abort_logs(struct list_head *logs, int err) |
1774 | int err) | ||
1775 | { | 1669 | { |
1776 | struct nilfs_segment_buffer *segbuf; | 1670 | struct nilfs_segment_buffer *segbuf; |
1777 | struct page *bd_page = NULL, *fs_page = NULL; | 1671 | struct page *bd_page = NULL, *fs_page = NULL; |
@@ -1801,8 +1695,6 @@ static void nilfs_abort_logs(struct list_head *logs, struct page *failed_page, | |||
1801 | } | 1695 | } |
1802 | if (bh->b_page != fs_page) { | 1696 | if (bh->b_page != fs_page) { |
1803 | nilfs_end_page_io(fs_page, err); | 1697 | nilfs_end_page_io(fs_page, err); |
1804 | if (fs_page && fs_page == failed_page) | ||
1805 | return; | ||
1806 | fs_page = bh->b_page; | 1698 | fs_page = bh->b_page; |
1807 | } | 1699 | } |
1808 | } | 1700 | } |
@@ -1821,12 +1713,11 @@ static void nilfs_segctor_abort_construction(struct nilfs_sc_info *sci, | |||
1821 | 1713 | ||
1822 | list_splice_tail_init(&sci->sc_write_logs, &logs); | 1714 | list_splice_tail_init(&sci->sc_write_logs, &logs); |
1823 | ret = nilfs_wait_on_logs(&logs); | 1715 | ret = nilfs_wait_on_logs(&logs); |
1824 | nilfs_abort_logs(&logs, NULL, ret ? : err); | 1716 | nilfs_abort_logs(&logs, ret ? : err); |
1825 | 1717 | ||
1826 | list_splice_tail_init(&sci->sc_segbufs, &logs); | 1718 | list_splice_tail_init(&sci->sc_segbufs, &logs); |
1827 | nilfs_cancel_segusage(&logs, nilfs->ns_sufile); | 1719 | nilfs_cancel_segusage(&logs, nilfs->ns_sufile); |
1828 | nilfs_free_incomplete_logs(&logs, nilfs); | 1720 | nilfs_free_incomplete_logs(&logs, nilfs); |
1829 | nilfs_clear_copied_buffers(&sci->sc_copied_buffers, err); | ||
1830 | 1721 | ||
1831 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { | 1722 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { |
1832 | ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, | 1723 | ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, |
@@ -1920,8 +1811,6 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
1920 | 1811 | ||
1921 | nilfs_end_page_io(fs_page, 0); | 1812 | nilfs_end_page_io(fs_page, 0); |
1922 | 1813 | ||
1923 | nilfs_clear_copied_buffers(&sci->sc_copied_buffers, 0); | ||
1924 | |||
1925 | nilfs_drop_collected_inodes(&sci->sc_dirty_files); | 1814 | nilfs_drop_collected_inodes(&sci->sc_dirty_files); |
1926 | 1815 | ||
1927 | if (nilfs_doing_gc()) | 1816 | if (nilfs_doing_gc()) |
@@ -2024,7 +1913,6 @@ static void nilfs_segctor_drop_written_files(struct nilfs_sc_info *sci, | |||
2024 | static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | 1913 | static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) |
2025 | { | 1914 | { |
2026 | struct the_nilfs *nilfs = sci->sc_super->s_fs_info; | 1915 | struct the_nilfs *nilfs = sci->sc_super->s_fs_info; |
2027 | struct page *failed_page; | ||
2028 | int err; | 1916 | int err; |
2029 | 1917 | ||
2030 | sci->sc_stage.scnt = NILFS_ST_INIT; | 1918 | sci->sc_stage.scnt = NILFS_ST_INIT; |
@@ -2079,11 +1967,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2079 | nilfs_segctor_update_segusage(sci, nilfs->ns_sufile); | 1967 | nilfs_segctor_update_segusage(sci, nilfs->ns_sufile); |
2080 | 1968 | ||
2081 | /* Write partial segments */ | 1969 | /* Write partial segments */ |
2082 | err = nilfs_segctor_prepare_write(sci, &failed_page); | 1970 | nilfs_segctor_prepare_write(sci); |
2083 | if (err) { | ||
2084 | nilfs_abort_logs(&sci->sc_segbufs, failed_page, err); | ||
2085 | goto failed_to_write; | ||
2086 | } | ||
2087 | 1971 | ||
2088 | nilfs_add_checksums_on_logs(&sci->sc_segbufs, | 1972 | nilfs_add_checksums_on_logs(&sci->sc_segbufs, |
2089 | nilfs->ns_crc_seed); | 1973 | nilfs->ns_crc_seed); |
@@ -2685,7 +2569,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb, | |||
2685 | INIT_LIST_HEAD(&sci->sc_segbufs); | 2569 | INIT_LIST_HEAD(&sci->sc_segbufs); |
2686 | INIT_LIST_HEAD(&sci->sc_write_logs); | 2570 | INIT_LIST_HEAD(&sci->sc_write_logs); |
2687 | INIT_LIST_HEAD(&sci->sc_gc_inodes); | 2571 | INIT_LIST_HEAD(&sci->sc_gc_inodes); |
2688 | INIT_LIST_HEAD(&sci->sc_copied_buffers); | ||
2689 | init_timer(&sci->sc_timer); | 2572 | init_timer(&sci->sc_timer); |
2690 | 2573 | ||
2691 | sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; | 2574 | sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; |
@@ -2739,8 +2622,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) | |||
2739 | if (flag || !nilfs_segctor_confirm(sci)) | 2622 | if (flag || !nilfs_segctor_confirm(sci)) |
2740 | nilfs_segctor_write_out(sci); | 2623 | nilfs_segctor_write_out(sci); |
2741 | 2624 | ||
2742 | WARN_ON(!list_empty(&sci->sc_copied_buffers)); | ||
2743 | |||
2744 | if (!list_empty(&sci->sc_dirty_files)) { | 2625 | if (!list_empty(&sci->sc_dirty_files)) { |
2745 | nilfs_warning(sci->sc_super, __func__, | 2626 | nilfs_warning(sci->sc_super, __func__, |
2746 | "dirty file(s) after the final construction\n"); | 2627 | "dirty file(s) after the final construction\n"); |