diff options
author | Chao Yu <chao2.yu@samsung.com> | 2014-05-26 20:41:07 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2014-06-04 00:34:30 -0400 |
commit | bac4eef6537a663585f3fb3d633a629c72e3b73d (patch) | |
tree | 40f3bd22e30d61eb1a485062b94e1f3c2cd97dd5 /fs/f2fs/node.c | |
parent | bfec07d0f8ed78b10df3ca3bc23e27de1166ea45 (diff) |
f2fs: avoid crash when trace f2fs_submit_page_mbio event in ra_sum_pages
Previously we allocate pages with no mapping in ra_sum_pages(), so we may
encounter a crash in event trace of f2fs_submit_page_mbio where we access
mapping data of the page.
We'd better allocate pages in bd_inode mapping and invalidate these pages after
we restore data from pages. It could avoid crash in above scenario.
Changes from V1
o remove redundant code in ra_sum_pages() suggested by Jaegeuk Kim.
Call Trace:
[<f1031630>] ? ftrace_raw_event_f2fs_write_checkpoint+0x80/0x80 [f2fs]
[<f10377bb>] f2fs_submit_page_mbio+0x1cb/0x200 [f2fs]
[<f103c5da>] restore_node_summary+0x13a/0x280 [f2fs]
[<f103e22d>] build_curseg+0x2bd/0x620 [f2fs]
[<f104043b>] build_segment_manager+0x1cb/0x920 [f2fs]
[<f1032c85>] f2fs_fill_super+0x535/0x8e0 [f2fs]
[<c115b66a>] mount_bdev+0x16a/0x1a0
[<f102f63f>] f2fs_mount+0x1f/0x30 [f2fs]
[<c115c096>] mount_fs+0x36/0x170
[<c1173635>] vfs_kern_mount+0x55/0xe0
[<c1175388>] do_mount+0x1e8/0x900
[<c1175d72>] SyS_mount+0x82/0xc0
[<c16059cc>] sysenter_do_call+0x12/0x22
Suggested-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/node.c')
-rw-r--r-- | fs/f2fs/node.c | 52 |
1 files changed, 24 insertions, 28 deletions
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 3d60d3d34ed2..02a59e9027b1 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c | |||
@@ -1658,35 +1658,29 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) | |||
1658 | 1658 | ||
1659 | /* | 1659 | /* |
1660 | * ra_sum_pages() merge contiguous pages into one bio and submit. | 1660 | * ra_sum_pages() merge contiguous pages into one bio and submit. |
1661 | * these pre-readed pages are linked in pages list. | 1661 | * these pre-readed pages are alloced in bd_inode's mapping tree. |
1662 | */ | 1662 | */ |
1663 | static int ra_sum_pages(struct f2fs_sb_info *sbi, struct list_head *pages, | 1663 | static int ra_sum_pages(struct f2fs_sb_info *sbi, struct page **pages, |
1664 | int start, int nrpages) | 1664 | int start, int nrpages) |
1665 | { | 1665 | { |
1666 | struct page *page; | 1666 | struct inode *inode = sbi->sb->s_bdev->bd_inode; |
1667 | int page_idx = start; | 1667 | struct address_space *mapping = inode->i_mapping; |
1668 | int i, page_idx = start; | ||
1668 | struct f2fs_io_info fio = { | 1669 | struct f2fs_io_info fio = { |
1669 | .type = META, | 1670 | .type = META, |
1670 | .rw = READ_SYNC | REQ_META | REQ_PRIO | 1671 | .rw = READ_SYNC | REQ_META | REQ_PRIO |
1671 | }; | 1672 | }; |
1672 | 1673 | ||
1673 | for (; page_idx < start + nrpages; page_idx++) { | 1674 | for (i = 0; page_idx < start + nrpages; page_idx++, i++) { |
1674 | /* alloc temporal page for read node summary info*/ | 1675 | /* alloc page in bd_inode for reading node summary info */ |
1675 | page = alloc_page(GFP_F2FS_ZERO); | 1676 | pages[i] = grab_cache_page(mapping, page_idx); |
1676 | if (!page) | 1677 | if (!pages[i]) |
1677 | break; | 1678 | break; |
1678 | 1679 | f2fs_submit_page_mbio(sbi, pages[i], page_idx, &fio); | |
1679 | lock_page(page); | ||
1680 | page->index = page_idx; | ||
1681 | list_add_tail(&page->lru, pages); | ||
1682 | } | 1680 | } |
1683 | 1681 | ||
1684 | list_for_each_entry(page, pages, lru) | ||
1685 | f2fs_submit_page_mbio(sbi, page, page->index, &fio); | ||
1686 | |||
1687 | f2fs_submit_merged_bio(sbi, META, READ); | 1682 | f2fs_submit_merged_bio(sbi, META, READ); |
1688 | 1683 | return i; | |
1689 | return page_idx - start; | ||
1690 | } | 1684 | } |
1691 | 1685 | ||
1692 | int restore_node_summary(struct f2fs_sb_info *sbi, | 1686 | int restore_node_summary(struct f2fs_sb_info *sbi, |
@@ -1694,11 +1688,11 @@ int restore_node_summary(struct f2fs_sb_info *sbi, | |||
1694 | { | 1688 | { |
1695 | struct f2fs_node *rn; | 1689 | struct f2fs_node *rn; |
1696 | struct f2fs_summary *sum_entry; | 1690 | struct f2fs_summary *sum_entry; |
1697 | struct page *page, *tmp; | 1691 | struct inode *inode = sbi->sb->s_bdev->bd_inode; |
1698 | block_t addr; | 1692 | block_t addr; |
1699 | int bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); | 1693 | int bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); |
1700 | int i, last_offset, nrpages, err = 0; | 1694 | struct page *pages[bio_blocks]; |
1701 | LIST_HEAD(page_list); | 1695 | int i, idx, last_offset, nrpages, err = 0; |
1702 | 1696 | ||
1703 | /* scan the node segment */ | 1697 | /* scan the node segment */ |
1704 | last_offset = sbi->blocks_per_seg; | 1698 | last_offset = sbi->blocks_per_seg; |
@@ -1709,29 +1703,31 @@ int restore_node_summary(struct f2fs_sb_info *sbi, | |||
1709 | nrpages = min(last_offset - i, bio_blocks); | 1703 | nrpages = min(last_offset - i, bio_blocks); |
1710 | 1704 | ||
1711 | /* read ahead node pages */ | 1705 | /* read ahead node pages */ |
1712 | nrpages = ra_sum_pages(sbi, &page_list, addr, nrpages); | 1706 | nrpages = ra_sum_pages(sbi, pages, addr, nrpages); |
1713 | if (!nrpages) | 1707 | if (!nrpages) |
1714 | return -ENOMEM; | 1708 | return -ENOMEM; |
1715 | 1709 | ||
1716 | list_for_each_entry_safe(page, tmp, &page_list, lru) { | 1710 | for (idx = 0; idx < nrpages; idx++) { |
1717 | if (err) | 1711 | if (err) |
1718 | goto skip; | 1712 | goto skip; |
1719 | 1713 | ||
1720 | lock_page(page); | 1714 | lock_page(pages[idx]); |
1721 | if (unlikely(!PageUptodate(page))) { | 1715 | if (unlikely(!PageUptodate(pages[idx]))) { |
1722 | err = -EIO; | 1716 | err = -EIO; |
1723 | } else { | 1717 | } else { |
1724 | rn = F2FS_NODE(page); | 1718 | rn = F2FS_NODE(pages[idx]); |
1725 | sum_entry->nid = rn->footer.nid; | 1719 | sum_entry->nid = rn->footer.nid; |
1726 | sum_entry->version = 0; | 1720 | sum_entry->version = 0; |
1727 | sum_entry->ofs_in_node = 0; | 1721 | sum_entry->ofs_in_node = 0; |
1728 | sum_entry++; | 1722 | sum_entry++; |
1729 | } | 1723 | } |
1730 | unlock_page(page); | 1724 | unlock_page(pages[idx]); |
1731 | skip: | 1725 | skip: |
1732 | list_del(&page->lru); | 1726 | page_cache_release(pages[idx]); |
1733 | __free_pages(page, 0); | ||
1734 | } | 1727 | } |
1728 | |||
1729 | invalidate_mapping_pages(inode->i_mapping, addr, | ||
1730 | addr + nrpages); | ||
1735 | } | 1731 | } |
1736 | return err; | 1732 | return err; |
1737 | } | 1733 | } |