.. | .. |
---|
7 | 7 | */ |
---|
8 | 8 | #include <linux/fs.h> |
---|
9 | 9 | #include <linux/module.h> |
---|
| 10 | +#include <linux/mount.h> |
---|
10 | 11 | #include <linux/backing-dev.h> |
---|
11 | 12 | #include <linux/init.h> |
---|
12 | 13 | #include <linux/f2fs_fs.h> |
---|
.. | .. |
---|
90 | 91 | * invalidated soon after by user update or deletion. |
---|
91 | 92 | * So, I'd like to wait some time to collect dirty segments. |
---|
92 | 93 | */ |
---|
93 | | - if (sbi->gc_mode == GC_URGENT_HIGH) { |
---|
| 94 | + if (sbi->gc_mode == GC_URGENT_HIGH || |
---|
| 95 | + sbi->gc_mode == GC_URGENT_MID) { |
---|
94 | 96 | wait_ms = gc_th->urgent_sleep_time; |
---|
95 | 97 | f2fs_down_write(&sbi->gc_lock); |
---|
96 | 98 | goto do_gc; |
---|
.. | .. |
---|
627 | 629 | f2fs_bug_on(sbi, !list_empty(&am->victim_list)); |
---|
628 | 630 | } |
---|
629 | 631 | |
---|
| 632 | +static bool f2fs_pin_section(struct f2fs_sb_info *sbi, unsigned int segno) |
---|
| 633 | +{ |
---|
| 634 | + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
---|
| 635 | + unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); |
---|
| 636 | + |
---|
| 637 | + if (!dirty_i->enable_pin_section) |
---|
| 638 | + return false; |
---|
| 639 | + if (!test_and_set_bit(secno, dirty_i->pinned_secmap)) |
---|
| 640 | + dirty_i->pinned_secmap_cnt++; |
---|
| 641 | + return true; |
---|
| 642 | +} |
---|
| 643 | + |
---|
| 644 | +static bool f2fs_pinned_section_exists(struct dirty_seglist_info *dirty_i) |
---|
| 645 | +{ |
---|
| 646 | + return dirty_i->pinned_secmap_cnt; |
---|
| 647 | +} |
---|
| 648 | + |
---|
| 649 | +static bool f2fs_section_is_pinned(struct dirty_seglist_info *dirty_i, |
---|
| 650 | + unsigned int secno) |
---|
| 651 | +{ |
---|
| 652 | + return dirty_i->enable_pin_section && |
---|
| 653 | + f2fs_pinned_section_exists(dirty_i) && |
---|
| 654 | + test_bit(secno, dirty_i->pinned_secmap); |
---|
| 655 | +} |
---|
| 656 | + |
---|
| 657 | +static void f2fs_unpin_all_sections(struct f2fs_sb_info *sbi, bool enable) |
---|
| 658 | +{ |
---|
| 659 | + unsigned int bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); |
---|
| 660 | + |
---|
| 661 | + if (f2fs_pinned_section_exists(DIRTY_I(sbi))) { |
---|
| 662 | + memset(DIRTY_I(sbi)->pinned_secmap, 0, bitmap_size); |
---|
| 663 | + DIRTY_I(sbi)->pinned_secmap_cnt = 0; |
---|
| 664 | + } |
---|
| 665 | + DIRTY_I(sbi)->enable_pin_section = enable; |
---|
| 666 | +} |
---|
| 667 | + |
---|
| 668 | +static int f2fs_gc_pinned_control(struct inode *inode, int gc_type, |
---|
| 669 | + unsigned int segno) |
---|
| 670 | +{ |
---|
| 671 | + if (!f2fs_is_pinned_file(inode)) |
---|
| 672 | + return 0; |
---|
| 673 | + if (gc_type != FG_GC) |
---|
| 674 | + return -EBUSY; |
---|
| 675 | + if (!f2fs_pin_section(F2FS_I_SB(inode), segno)) |
---|
| 676 | + f2fs_pin_file_control(inode, true); |
---|
| 677 | + return -EAGAIN; |
---|
| 678 | +} |
---|
| 679 | + |
---|
630 | 680 | /* |
---|
631 | 681 | * This function is called from two paths. |
---|
632 | 682 | * One is garbage collection and the other is SSR segment selection. |
---|
.. | .. |
---|
766 | 816 | } |
---|
767 | 817 | |
---|
768 | 818 | if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap)) |
---|
| 819 | + goto next; |
---|
| 820 | + |
---|
| 821 | + if (gc_type == FG_GC && f2fs_section_is_pinned(dirty_i, secno)) |
---|
769 | 822 | goto next; |
---|
770 | 823 | |
---|
771 | 824 | if (is_atgc) { |
---|
.. | .. |
---|
1000 | 1053 | { |
---|
1001 | 1054 | struct page *node_page; |
---|
1002 | 1055 | nid_t nid; |
---|
1003 | | - unsigned int ofs_in_node, max_addrs; |
---|
| 1056 | + unsigned int ofs_in_node, max_addrs, base; |
---|
1004 | 1057 | block_t source_blkaddr; |
---|
1005 | 1058 | |
---|
1006 | 1059 | nid = le32_to_cpu(sum->nid); |
---|
.. | .. |
---|
1026 | 1079 | return false; |
---|
1027 | 1080 | } |
---|
1028 | 1081 | |
---|
1029 | | - max_addrs = IS_INODE(node_page) ? DEF_ADDRS_PER_INODE : |
---|
1030 | | - DEF_ADDRS_PER_BLOCK; |
---|
1031 | | - if (ofs_in_node >= max_addrs) { |
---|
1032 | | - f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u", |
---|
1033 | | - ofs_in_node, dni->ino, dni->nid, max_addrs); |
---|
| 1082 | + if (IS_INODE(node_page)) { |
---|
| 1083 | + base = offset_in_addr(F2FS_INODE(node_page)); |
---|
| 1084 | + max_addrs = DEF_ADDRS_PER_INODE; |
---|
| 1085 | + } else { |
---|
| 1086 | + base = 0; |
---|
| 1087 | + max_addrs = DEF_ADDRS_PER_BLOCK; |
---|
| 1088 | + } |
---|
| 1089 | + |
---|
| 1090 | + if (base + ofs_in_node >= max_addrs) { |
---|
| 1091 | + f2fs_err(sbi, "Inconsistent blkaddr offset: base:%u, ofs_in_node:%u, max:%u, ino:%u, nid:%u", |
---|
| 1092 | + base, ofs_in_node, max_addrs, dni->ino, dni->nid); |
---|
| 1093 | + f2fs_put_page(node_page, 1); |
---|
1034 | 1094 | return false; |
---|
1035 | 1095 | } |
---|
1036 | 1096 | |
---|
.. | .. |
---|
1189 | 1249 | goto out; |
---|
1190 | 1250 | } |
---|
1191 | 1251 | |
---|
1192 | | - if (f2fs_is_pinned_file(inode)) { |
---|
1193 | | - if (gc_type == FG_GC) |
---|
1194 | | - f2fs_pin_file_control(inode, true); |
---|
1195 | | - err = -EAGAIN; |
---|
| 1252 | + err = f2fs_gc_pinned_control(inode, gc_type, segno); |
---|
| 1253 | + if (err) |
---|
1196 | 1254 | goto out; |
---|
1197 | | - } |
---|
1198 | 1255 | |
---|
1199 | 1256 | set_new_dnode(&dn, inode, NULL, NULL, 0); |
---|
1200 | 1257 | err = f2fs_get_dnode_of_data(&dn, bidx, LOOKUP_NODE); |
---|
.. | .. |
---|
1339 | 1396 | err = -EAGAIN; |
---|
1340 | 1397 | goto out; |
---|
1341 | 1398 | } |
---|
1342 | | - if (f2fs_is_pinned_file(inode)) { |
---|
1343 | | - if (gc_type == FG_GC) |
---|
1344 | | - f2fs_pin_file_control(inode, true); |
---|
1345 | | - err = -EAGAIN; |
---|
| 1399 | + err = f2fs_gc_pinned_control(inode, gc_type, segno); |
---|
| 1400 | + if (err) |
---|
1346 | 1401 | goto out; |
---|
1347 | | - } |
---|
1348 | 1402 | |
---|
1349 | 1403 | if (gc_type == BG_GC) { |
---|
1350 | 1404 | if (PageWriteback(page)) { |
---|
.. | .. |
---|
1465 | 1519 | ofs_in_node = le16_to_cpu(entry->ofs_in_node); |
---|
1466 | 1520 | |
---|
1467 | 1521 | if (phase == 3) { |
---|
| 1522 | + int err; |
---|
| 1523 | + |
---|
1468 | 1524 | inode = f2fs_iget(sb, dni.ino); |
---|
1469 | 1525 | if (IS_ERR(inode) || is_bad_inode(inode)) |
---|
1470 | 1526 | continue; |
---|
| 1527 | + |
---|
| 1528 | + err = f2fs_gc_pinned_control(inode, gc_type, segno); |
---|
| 1529 | + if (err == -EAGAIN) { |
---|
| 1530 | + iput(inode); |
---|
| 1531 | + return submitted; |
---|
| 1532 | + } |
---|
1471 | 1533 | |
---|
1472 | 1534 | if (!f2fs_down_write_trylock( |
---|
1473 | 1535 | &F2FS_I(inode)->i_gc_rwsem[WRITE])) { |
---|
.. | .. |
---|
1672 | 1734 | get_valid_blocks(sbi, segno, false) == 0) |
---|
1673 | 1735 | seg_freed++; |
---|
1674 | 1736 | |
---|
1675 | | - if (__is_large_section(sbi) && segno + 1 < end_segno) |
---|
1676 | | - sbi->next_victim_seg[gc_type] = segno + 1; |
---|
| 1737 | + if (__is_large_section(sbi)) |
---|
| 1738 | + sbi->next_victim_seg[gc_type] = |
---|
| 1739 | + (segno + 1 < end_segno) ? segno + 1 : NULL_SEGNO; |
---|
1677 | 1740 | skip: |
---|
1678 | 1741 | f2fs_put_page(sum_page, 0); |
---|
1679 | 1742 | } |
---|
.. | .. |
---|
1748 | 1811 | ret = -EINVAL; |
---|
1749 | 1812 | goto stop; |
---|
1750 | 1813 | } |
---|
| 1814 | +retry: |
---|
1751 | 1815 | ret = __get_victim(sbi, &segno, gc_type); |
---|
1752 | | - if (ret) |
---|
| 1816 | + if (ret) { |
---|
| 1817 | + /* allow to search victim from sections has pinned data */ |
---|
| 1818 | + if (ret == -ENODATA && gc_type == FG_GC && |
---|
| 1819 | + f2fs_pinned_section_exists(DIRTY_I(sbi))) { |
---|
| 1820 | + f2fs_unpin_all_sections(sbi, false); |
---|
| 1821 | + goto retry; |
---|
| 1822 | + } |
---|
1753 | 1823 | goto stop; |
---|
| 1824 | + } |
---|
1754 | 1825 | |
---|
1755 | 1826 | seg_freed = do_garbage_collect(sbi, segno, &gc_list, gc_type, force); |
---|
1756 | 1827 | if (gc_type == FG_GC && |
---|
.. | .. |
---|
1800 | 1871 | stop: |
---|
1801 | 1872 | SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0; |
---|
1802 | 1873 | SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno; |
---|
| 1874 | + |
---|
| 1875 | + if (gc_type == FG_GC) |
---|
| 1876 | + f2fs_unpin_all_sections(sbi, true); |
---|
1803 | 1877 | |
---|
1804 | 1878 | trace_f2fs_gc_end(sbi->sb, ret, total_freed, sec_freed, |
---|
1805 | 1879 | get_pages(sbi, F2FS_DIRTY_NODES), |
---|
.. | .. |
---|
1991 | 2065 | } |
---|
1992 | 2066 | } |
---|
1993 | 2067 | |
---|
1994 | | -int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count) |
---|
| 2068 | +int f2fs_resize_fs(struct file *filp, __u64 block_count) |
---|
1995 | 2069 | { |
---|
| 2070 | + struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp)); |
---|
1996 | 2071 | __u64 old_block_count, shrunk_blocks; |
---|
1997 | 2072 | struct cp_control cpc = { CP_RESIZE, 0, 0, 0 }; |
---|
1998 | 2073 | unsigned int secs; |
---|
.. | .. |
---|
2030 | 2105 | return -EINVAL; |
---|
2031 | 2106 | } |
---|
2032 | 2107 | |
---|
| 2108 | + err = mnt_want_write_file(filp); |
---|
| 2109 | + if (err) |
---|
| 2110 | + return err; |
---|
| 2111 | + |
---|
2033 | 2112 | shrunk_blocks = old_block_count - block_count; |
---|
2034 | 2113 | secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi)); |
---|
2035 | 2114 | |
---|
2036 | 2115 | /* stop other GC */ |
---|
2037 | | - if (!f2fs_down_write_trylock(&sbi->gc_lock)) |
---|
2038 | | - return -EAGAIN; |
---|
| 2116 | + if (!f2fs_down_write_trylock(&sbi->gc_lock)) { |
---|
| 2117 | + err = -EAGAIN; |
---|
| 2118 | + goto out_drop_write; |
---|
| 2119 | + } |
---|
2039 | 2120 | |
---|
2040 | 2121 | /* stop CP to protect MAIN_SEC in free_segment_range */ |
---|
2041 | 2122 | f2fs_lock_op(sbi); |
---|
.. | .. |
---|
2055 | 2136 | out_unlock: |
---|
2056 | 2137 | f2fs_unlock_op(sbi); |
---|
2057 | 2138 | f2fs_up_write(&sbi->gc_lock); |
---|
| 2139 | +out_drop_write: |
---|
| 2140 | + mnt_drop_write_file(filp); |
---|
2058 | 2141 | if (err) |
---|
2059 | 2142 | return err; |
---|
2060 | 2143 | |
---|
2061 | | - set_sbi_flag(sbi, SBI_IS_RESIZEFS); |
---|
2062 | | - |
---|
2063 | 2144 | freeze_super(sbi->sb); |
---|
| 2145 | + |
---|
| 2146 | + if (f2fs_readonly(sbi->sb)) { |
---|
| 2147 | + thaw_super(sbi->sb); |
---|
| 2148 | + return -EROFS; |
---|
| 2149 | + } |
---|
| 2150 | + |
---|
2064 | 2151 | f2fs_down_write(&sbi->gc_lock); |
---|
2065 | 2152 | f2fs_down_write(&sbi->cp_global_sem); |
---|
2066 | 2153 | |
---|
.. | .. |
---|
2075 | 2162 | if (err) |
---|
2076 | 2163 | goto out_err; |
---|
2077 | 2164 | |
---|
| 2165 | + set_sbi_flag(sbi, SBI_IS_RESIZEFS); |
---|
2078 | 2166 | err = free_segment_range(sbi, secs, false); |
---|
2079 | 2167 | if (err) |
---|
2080 | 2168 | goto recover_out; |
---|
.. | .. |
---|
2098 | 2186 | f2fs_commit_super(sbi, false); |
---|
2099 | 2187 | } |
---|
2100 | 2188 | recover_out: |
---|
| 2189 | + clear_sbi_flag(sbi, SBI_IS_RESIZEFS); |
---|
2101 | 2190 | if (err) { |
---|
2102 | 2191 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
---|
2103 | 2192 | f2fs_err(sbi, "resize_fs failed, should run fsck to repair!"); |
---|
.. | .. |
---|
2110 | 2199 | f2fs_up_write(&sbi->cp_global_sem); |
---|
2111 | 2200 | f2fs_up_write(&sbi->gc_lock); |
---|
2112 | 2201 | thaw_super(sbi->sb); |
---|
2113 | | - clear_sbi_flag(sbi, SBI_IS_RESIZEFS); |
---|
2114 | 2202 | return err; |
---|
2115 | 2203 | } |
---|