Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

f2fs: revert summary entry count from 2048 to 512 in 16kb block support

The recent increase in the number of Segment Summary Area (SSA) entries
from 512 to 2048 was an unintentional change in logic of 16kb block
support. This commit corrects the issue.

To better utilize the space available from the erroneous 2048-entry
calculation, we are implementing a solution to share the currently
unused SSA space with neighboring segments. This enhances overall
SSA utilization without impacting the established 8MB segment size.

Fixes: d7e9a9037de2 ("f2fs: Support Block Size == Page Size")
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Daeho Jeong and committed by
Jaegeuk Kim
7ee8bc39 68d05693

+129 -62
+2
fs/f2fs/f2fs.h
··· 245 245 #define F2FS_FEATURE_COMPRESSION 0x00002000 246 246 #define F2FS_FEATURE_RO 0x00004000 247 247 #define F2FS_FEATURE_DEVICE_ALIAS 0x00008000 248 + #define F2FS_FEATURE_PACKED_SSA 0x00010000 248 249 249 250 #define __F2FS_HAS_FEATURE(raw_super, mask) \ 250 251 ((raw_super->feature & cpu_to_le32(mask)) != 0) ··· 4705 4704 F2FS_FEATURE_FUNCS(compression, COMPRESSION); 4706 4705 F2FS_FEATURE_FUNCS(readonly, RO); 4707 4706 F2FS_FEATURE_FUNCS(device_alias, DEVICE_ALIAS); 4707 + F2FS_FEATURE_FUNCS(packed_ssa, PACKED_SSA); 4708 4708 4709 4709 #ifdef CONFIG_BLK_DEV_ZONED 4710 4710 static inline bool f2fs_zone_is_seq(struct f2fs_sb_info *sbi, int devi,
+68 -47
fs/f2fs/gc.c
··· 1735 1735 unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? 1736 1736 SUM_TYPE_DATA : SUM_TYPE_NODE; 1737 1737 unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE; 1738 - int submitted = 0; 1738 + int submitted = 0, sum_blk_cnt; 1739 1739 1740 1740 if (__is_large_section(sbi)) { 1741 1741 sec_end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi)); ··· 1769 1769 1770 1770 sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); 1771 1771 1772 + segno = rounddown(segno, SUMS_PER_BLOCK); 1773 + sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK); 1772 1774 /* readahead multi ssa blocks those have contiguous address */ 1773 1775 if (__is_large_section(sbi)) 1774 1776 f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), 1775 - end_segno - segno, META_SSA, true); 1777 + sum_blk_cnt, META_SSA, true); 1776 1778 1777 1779 /* reference all summary page */ 1778 1780 while (segno < end_segno) { 1779 - struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno++); 1781 + struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno); 1782 + 1783 + segno += SUMS_PER_BLOCK; 1780 1784 if (IS_ERR(sum_folio)) { 1781 1785 int err = PTR_ERR(sum_folio); 1782 1786 1783 - end_segno = segno - 1; 1784 - for (segno = start_segno; segno < end_segno; segno++) { 1787 + end_segno = segno - SUMS_PER_BLOCK; 1788 + segno = rounddown(start_segno, SUMS_PER_BLOCK); 1789 + while (segno < end_segno) { 1785 1790 sum_folio = filemap_get_folio(META_MAPPING(sbi), 1786 1791 GET_SUM_BLOCK(sbi, segno)); 1787 1792 folio_put_refs(sum_folio, 2); 1793 + segno += SUMS_PER_BLOCK; 1788 1794 } 1789 1795 return err; 1790 1796 } ··· 1799 1793 1800 1794 blk_start_plug(&plug); 1801 1795 1802 - for (segno = start_segno; segno < end_segno; segno++) { 1803 - struct f2fs_summary_block *sum; 1796 + segno = start_segno; 1797 + while (segno < end_segno) { 1798 + unsigned int cur_segno; 1804 1799 1805 1800 /* find segment summary of victim */ 1806 1801 struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi), 1807 1802 GET_SUM_BLOCK(sbi, segno)); 1803 + unsigned int block_end_segno = rounddown(segno, SUMS_PER_BLOCK) 1804 + + SUMS_PER_BLOCK; 1805 + 1806 + if (block_end_segno > end_segno) 1807 + block_end_segno = end_segno; 1808 1808 1809 1809 if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, segno))) { 1810 1810 f2fs_err(sbi, "%s: segment %u is used by log", 1811 1811 __func__, segno); 1812 1812 f2fs_bug_on(sbi, 1); 1813 - goto skip; 1813 + goto next_block; 1814 1814 } 1815 1815 1816 - if (get_valid_blocks(sbi, segno, false) == 0) 1817 - goto freed; 1818 - if (gc_type == BG_GC && __is_large_section(sbi) && 1819 - migrated >= sbi->migration_granularity) 1820 - goto skip; 1821 1816 if (!folio_test_uptodate(sum_folio) || 1822 1817 unlikely(f2fs_cp_error(sbi))) 1823 - goto skip; 1818 + goto next_block; 1824 1819 1825 - sum = folio_address(sum_folio); 1826 - if (type != GET_SUM_TYPE((&sum->footer))) { 1827 - f2fs_err(sbi, "Inconsistent segment (%u) type [%d, %d] in SIT and SSA", 1828 - segno, type, GET_SUM_TYPE((&sum->footer))); 1829 - f2fs_stop_checkpoint(sbi, false, 1830 - STOP_CP_REASON_CORRUPTED_SUMMARY); 1831 - goto skip; 1832 - } 1820 + for (cur_segno = segno; cur_segno < block_end_segno; 1821 + cur_segno++) { 1822 + struct f2fs_summary_block *sum; 1833 1823 1834 - /* 1835 - * this is to avoid deadlock: 1836 - * - lock_page(sum_page) - f2fs_replace_block 1837 - * - check_valid_map() - down_write(sentry_lock) 1838 - * - down_read(sentry_lock) - change_curseg() 1839 - * - lock_page(sum_page) 1840 - */ 1841 - if (type == SUM_TYPE_NODE) 1842 - submitted += gc_node_segment(sbi, sum->entries, segno, 1843 - gc_type); 1844 - else 1845 - submitted += gc_data_segment(sbi, sum->entries, gc_list, 1846 - segno, gc_type, 1847 - force_migrate); 1824 + if (get_valid_blocks(sbi, cur_segno, false) == 0) 1825 + goto freed; 1826 + if (gc_type == BG_GC && __is_large_section(sbi) && 1827 + migrated >= sbi->migration_granularity) 1828 + continue; 1848 1829 1849 - stat_inc_gc_seg_count(sbi, data_type, gc_type); 1850 - sbi->gc_reclaimed_segs[sbi->gc_mode]++; 1851 - migrated++; 1830 + sum = SUM_BLK_PAGE_ADDR(sum_folio, cur_segno); 1831 + if (type != GET_SUM_TYPE((&sum->footer))) { 1832 + f2fs_err(sbi, "Inconsistent segment (%u) type " 1833 + "[%d, %d] in SSA and SIT", 1834 + cur_segno, type, 1835 + GET_SUM_TYPE((&sum->footer))); 1836 + f2fs_stop_checkpoint(sbi, false, 1837 + STOP_CP_REASON_CORRUPTED_SUMMARY); 1838 + continue; 1839 + } 1840 + 1841 + /* 1842 + * this is to avoid deadlock: 1843 + * - lock_page(sum_page) - f2fs_replace_block 1844 + * - check_valid_map() - down_write(sentry_lock) 1845 + * - down_read(sentry_lock) - change_curseg() 1846 + * - lock_page(sum_page) 1847 + */ 1848 + if (type == SUM_TYPE_NODE) 1849 + submitted += gc_node_segment(sbi, sum->entries, 1850 + cur_segno, gc_type); 1851 + else 1852 + submitted += gc_data_segment(sbi, sum->entries, 1853 + gc_list, cur_segno, 1854 + gc_type, force_migrate); 1855 + 1856 + stat_inc_gc_seg_count(sbi, data_type, gc_type); 1857 + sbi->gc_reclaimed_segs[sbi->gc_mode]++; 1858 + migrated++; 1852 1859 1853 1860 freed: 1854 - if (gc_type == FG_GC && 1855 - get_valid_blocks(sbi, segno, false) == 0) 1856 - seg_freed++; 1861 + if (gc_type == FG_GC && 1862 + get_valid_blocks(sbi, cur_segno, false) == 0) 1863 + seg_freed++; 1857 1864 1858 - if (__is_large_section(sbi)) 1859 - sbi->next_victim_seg[gc_type] = 1860 - (segno + 1 < sec_end_segno) ? 1861 - segno + 1 : NULL_SEGNO; 1862 - skip: 1865 + if (__is_large_section(sbi)) 1866 + sbi->next_victim_seg[gc_type] = 1867 + (cur_segno + 1 < sec_end_segno) ? 1868 + cur_segno + 1 : NULL_SEGNO; 1869 + } 1870 + next_block: 1863 1871 folio_put_refs(sum_folio, 2); 1872 + segno = block_end_segno; 1864 1873 } 1865 1874 1866 1875 if (submitted)
+1 -1
fs/f2fs/recovery.c
··· 522 522 sum_folio = f2fs_get_sum_folio(sbi, segno); 523 523 if (IS_ERR(sum_folio)) 524 524 return PTR_ERR(sum_folio); 525 - sum_node = folio_address(sum_folio); 525 + sum_node = SUM_BLK_PAGE_ADDR(sum_folio, segno); 526 526 sum = sum_node->entries[blkoff]; 527 527 f2fs_folio_put(sum_folio, true); 528 528 got_it:
+28 -10
fs/f2fs/segment.c
··· 2712 2712 void f2fs_update_meta_page(struct f2fs_sb_info *sbi, 2713 2713 void *src, block_t blk_addr) 2714 2714 { 2715 - struct folio *folio = f2fs_grab_meta_folio(sbi, blk_addr); 2715 + struct folio *folio; 2716 + 2717 + if (SUMS_PER_BLOCK == 1) 2718 + folio = f2fs_grab_meta_folio(sbi, blk_addr); 2719 + else 2720 + folio = f2fs_get_meta_folio_retry(sbi, blk_addr); 2721 + 2722 + if (IS_ERR(folio)) 2723 + return; 2716 2724 2717 2725 memcpy(folio_address(folio), src, PAGE_SIZE); 2718 2726 folio_mark_dirty(folio); ··· 2728 2720 } 2729 2721 2730 2722 static void write_sum_page(struct f2fs_sb_info *sbi, 2731 - struct f2fs_summary_block *sum_blk, block_t blk_addr) 2723 + struct f2fs_summary_block *sum_blk, unsigned int segno) 2732 2724 { 2733 - f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr); 2725 + struct folio *folio; 2726 + 2727 + if (SUMS_PER_BLOCK == 1) 2728 + return f2fs_update_meta_page(sbi, (void *)sum_blk, 2729 + GET_SUM_BLOCK(sbi, segno)); 2730 + 2731 + folio = f2fs_get_sum_folio(sbi, segno); 2732 + if (IS_ERR(folio)) 2733 + return; 2734 + 2735 + memcpy(SUM_BLK_PAGE_ADDR(folio, segno), sum_blk, sizeof(*sum_blk)); 2736 + folio_mark_dirty(folio); 2737 + f2fs_folio_put(folio, true); 2734 2738 } 2735 2739 2736 2740 static void write_current_sum_page(struct f2fs_sb_info *sbi, ··· 3007 2987 int ret; 3008 2988 3009 2989 if (curseg->inited) 3010 - write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno)); 2990 + write_sum_page(sbi, curseg->sum_blk, segno); 3011 2991 3012 2992 segno = __get_next_segno(sbi, type); 3013 2993 ret = get_new_segment(sbi, &segno, new_sec, pinning); ··· 3066 3046 struct folio *sum_folio; 3067 3047 3068 3048 if (curseg->inited) 3069 - write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno)); 3049 + write_sum_page(sbi, curseg->sum_blk, curseg->segno); 3070 3050 3071 3051 __set_test_and_inuse(sbi, new_segno); 3072 3052 ··· 3085 3065 memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE); 3086 3066 return PTR_ERR(sum_folio); 3087 3067 } 3088 - sum_node = folio_address(sum_folio); 3068 + sum_node = SUM_BLK_PAGE_ADDR(sum_folio, new_segno); 3089 3069 memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); 3090 3070 f2fs_folio_put(sum_folio, true); 3091 3071 return 0; ··· 3174 3154 goto out; 3175 3155 3176 3156 if (get_valid_blocks(sbi, curseg->segno, false)) { 3177 - write_sum_page(sbi, curseg->sum_blk, 3178 - GET_SUM_BLOCK(sbi, curseg->segno)); 3157 + write_sum_page(sbi, curseg->sum_blk, curseg->segno); 3179 3158 } else { 3180 3159 mutex_lock(&DIRTY_I(sbi)->seglist_lock); 3181 3160 __set_test_and_free(sbi, curseg->segno, true); ··· 3852 3833 if (segment_full) { 3853 3834 if (type == CURSEG_COLD_DATA_PINNED && 3854 3835 !((curseg->segno + 1) % sbi->segs_per_sec)) { 3855 - write_sum_page(sbi, curseg->sum_blk, 3856 - GET_SUM_BLOCK(sbi, curseg->segno)); 3836 + write_sum_page(sbi, curseg->sum_blk, curseg->segno); 3857 3837 reset_curseg_fields(curseg); 3858 3838 goto skip_new_segment; 3859 3839 }
+6 -2
fs/f2fs/segment.h
··· 85 85 #define GET_ZONE_FROM_SEG(sbi, segno) \ 86 86 GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno)) 87 87 88 - #define GET_SUM_BLOCK(sbi, segno) \ 89 - ((sbi)->sm_info->ssa_blkaddr + (segno)) 88 + #define SUMS_PER_BLOCK (F2FS_BLKSIZE / F2FS_SUM_BLKSIZE) 89 + #define GET_SUM_BLOCK(sbi, segno) \ 90 + (SM_I(sbi)->ssa_blkaddr + (segno / SUMS_PER_BLOCK)) 91 + #define GET_SUM_BLKOFF(segno) (segno % SUMS_PER_BLOCK) 92 + #define SUM_BLK_PAGE_ADDR(folio, segno) \ 93 + (folio_address(folio) + GET_SUM_BLKOFF(segno) * F2FS_SUM_BLKSIZE) 90 94 91 95 #define GET_SUM_TYPE(footer) ((footer)->entry_type) 92 96 #define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type))
+14
fs/f2fs/super.c
··· 4080 4080 if (sanity_check_area_boundary(sbi, folio, index)) 4081 4081 return -EFSCORRUPTED; 4082 4082 4083 + /* 4084 + * Check for legacy summary layout on 16KB+ block devices. 4085 + * Modern f2fs-tools packs multiple 4KB summary areas into one block, 4086 + * whereas legacy versions used one block per summary, leading 4087 + * to a much larger SSA. 4088 + */ 4089 + if (SUMS_PER_BLOCK > 1 && 4090 + !(__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_PACKED_SSA))) { 4091 + f2fs_info(sbi, "Error: Device formatted with a legacy version. " 4092 + "Please reformat with a tool supporting the packed ssa " 4093 + "feature for block sizes larger than 4kb."); 4094 + return -EOPNOTSUPP; 4095 + } 4096 + 4083 4097 return 0; 4084 4098 } 4085 4099
+7
fs/f2fs/sysfs.c
··· 235 235 if (f2fs_sb_has_compression(sbi)) 236 236 len += sysfs_emit_at(buf, len, "%s%s", 237 237 len ? ", " : "", "compression"); 238 + if (f2fs_sb_has_packed_ssa(sbi)) 239 + len += sysfs_emit_at(buf, len, "%s%s", 240 + len ? ", " : "", "packed_ssa"); 238 241 len += sysfs_emit_at(buf, len, "%s%s", 239 242 len ? ", " : "", "pin_file"); 240 243 len += sysfs_emit_at(buf, len, "\n"); ··· 1299 1296 #ifdef CONFIG_UNICODE 1300 1297 F2FS_FEATURE_RO_ATTR(linear_lookup); 1301 1298 #endif 1299 + F2FS_FEATURE_RO_ATTR(packed_ssa); 1302 1300 1303 1301 #define ATTR_LIST(name) (&f2fs_attr_##name.attr) 1304 1302 static struct attribute *f2fs_attrs[] = { ··· 1459 1455 #ifdef CONFIG_UNICODE 1460 1456 BASE_ATTR_LIST(linear_lookup), 1461 1457 #endif 1458 + BASE_ATTR_LIST(packed_ssa), 1462 1459 NULL, 1463 1460 }; 1464 1461 ATTRIBUTE_GROUPS(f2fs_feat); ··· 1495 1490 F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION); 1496 1491 F2FS_SB_FEATURE_RO_ATTR(readonly, RO); 1497 1492 F2FS_SB_FEATURE_RO_ATTR(device_alias, DEVICE_ALIAS); 1493 + F2FS_SB_FEATURE_RO_ATTR(packed_ssa, PACKED_SSA); 1498 1494 1499 1495 static struct attribute *f2fs_sb_feat_attrs[] = { 1500 1496 ATTR_LIST(sb_encryption), ··· 1513 1507 ATTR_LIST(sb_compression), 1514 1508 ATTR_LIST(sb_readonly), 1515 1509 ATTR_LIST(sb_device_alias), 1510 + ATTR_LIST(sb_packed_ssa), 1516 1511 NULL, 1517 1512 }; 1518 1513 ATTRIBUTE_GROUPS(f2fs_sb_feat);
+3 -2
include/linux/f2fs_fs.h
··· 17 17 #define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */ 18 18 #define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */ 19 19 #define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */ 20 + #define F2FS_SUM_BLKSIZE 4096 /* only support 4096 byte sum block */ 20 21 #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ 21 22 #define F2FS_EXTENSION_LEN 8 /* max size of extension */ 22 23 ··· 442 441 * from node's page's beginning to get a data block address. 443 442 * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) 444 443 */ 445 - #define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8) 444 + #define ENTRIES_IN_SUM (F2FS_SUM_BLKSIZE / 8) 446 445 #define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */ 447 446 #define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ 448 447 #define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) ··· 468 467 __le32 check_sum; /* summary checksum */ 469 468 } __packed; 470 469 471 - #define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ 470 + #define SUM_JOURNAL_SIZE (F2FS_SUM_BLKSIZE - SUM_FOOTER_SIZE -\ 472 471 SUM_ENTRY_SIZE) 473 472 #define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ 474 473 sizeof(struct nat_journal_entry))