Skip to content

Commit 7ee8bc3

Browse files
Daeho JeongJaegeuk Kim
authored andcommitted
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: d7e9a90 ("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>
1 parent 68d0569 commit 7ee8bc3

8 files changed

Lines changed: 130 additions & 63 deletions

File tree

fs/f2fs/f2fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ struct f2fs_mount_info {
245245
#define F2FS_FEATURE_COMPRESSION 0x00002000
246246
#define F2FS_FEATURE_RO 0x00004000
247247
#define F2FS_FEATURE_DEVICE_ALIAS 0x00008000
248+
#define F2FS_FEATURE_PACKED_SSA 0x00010000
248249

249250
#define __F2FS_HAS_FEATURE(raw_super, mask) \
250251
((raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -4704,6 +4705,7 @@ F2FS_FEATURE_FUNCS(casefold, CASEFOLD);
47044705
F2FS_FEATURE_FUNCS(compression, COMPRESSION);
47054706
F2FS_FEATURE_FUNCS(readonly, RO);
47064707
F2FS_FEATURE_FUNCS(device_alias, DEVICE_ALIAS);
4708+
F2FS_FEATURE_FUNCS(packed_ssa, PACKED_SSA);
47074709

47084710
#ifdef CONFIG_BLK_DEV_ZONED
47094711
static inline bool f2fs_zone_is_seq(struct f2fs_sb_info *sbi, int devi,

fs/f2fs/gc.c

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,7 +1735,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
17351735
unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
17361736
SUM_TYPE_DATA : SUM_TYPE_NODE;
17371737
unsigned char data_type = (type == SUM_TYPE_DATA) ? DATA : NODE;
1738-
int submitted = 0;
1738+
int submitted = 0, sum_blk_cnt;
17391739

17401740
if (__is_large_section(sbi)) {
17411741
sec_end_segno = rounddown(end_segno, SEGS_PER_SEC(sbi));
@@ -1769,22 +1769,28 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
17691769

17701770
sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type);
17711771

1772+
segno = rounddown(segno, SUMS_PER_BLOCK);
1773+
sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK);
17721774
/* readahead multi ssa blocks those have contiguous address */
17731775
if (__is_large_section(sbi))
17741776
f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
1775-
end_segno - segno, META_SSA, true);
1777+
sum_blk_cnt, META_SSA, true);
17761778

17771779
/* reference all summary page */
17781780
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;
17801784
if (IS_ERR(sum_folio)) {
17811785
int err = PTR_ERR(sum_folio);
17821786

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) {
17851790
sum_folio = filemap_get_folio(META_MAPPING(sbi),
17861791
GET_SUM_BLOCK(sbi, segno));
17871792
folio_put_refs(sum_folio, 2);
1793+
segno += SUMS_PER_BLOCK;
17881794
}
17891795
return err;
17901796
}
@@ -1793,68 +1799,83 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
17931799

17941800
blk_start_plug(&plug);
17951801

1796-
for (segno = start_segno; segno < end_segno; segno++) {
1797-
struct f2fs_summary_block *sum;
1802+
segno = start_segno;
1803+
while (segno < end_segno) {
1804+
unsigned int cur_segno;
17981805

17991806
/* find segment summary of victim */
18001807
struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi),
18011808
GET_SUM_BLOCK(sbi, segno));
1809+
unsigned int block_end_segno = rounddown(segno, SUMS_PER_BLOCK)
1810+
+ SUMS_PER_BLOCK;
1811+
1812+
if (block_end_segno > end_segno)
1813+
block_end_segno = end_segno;
18021814

18031815
if (is_cursec(sbi, GET_SEC_FROM_SEG(sbi, segno))) {
18041816
f2fs_err(sbi, "%s: segment %u is used by log",
18051817
__func__, segno);
18061818
f2fs_bug_on(sbi, 1);
1807-
goto skip;
1819+
goto next_block;
18081820
}
18091821

1810-
if (get_valid_blocks(sbi, segno, false) == 0)
1811-
goto freed;
1812-
if (gc_type == BG_GC && __is_large_section(sbi) &&
1813-
migrated >= sbi->migration_granularity)
1814-
goto skip;
18151822
if (!folio_test_uptodate(sum_folio) ||
18161823
unlikely(f2fs_cp_error(sbi)))
1817-
goto skip;
1824+
goto next_block;
18181825

1819-
sum = folio_address(sum_folio);
1820-
if (type != GET_SUM_TYPE((&sum->footer))) {
1821-
f2fs_err(sbi, "Inconsistent segment (%u) type [%d, %d] in SIT and SSA",
1822-
segno, type, GET_SUM_TYPE((&sum->footer)));
1823-
f2fs_stop_checkpoint(sbi, false,
1824-
STOP_CP_REASON_CORRUPTED_SUMMARY);
1825-
goto skip;
1826-
}
1826+
for (cur_segno = segno; cur_segno < block_end_segno;
1827+
cur_segno++) {
1828+
struct f2fs_summary_block *sum;
18271829

1828-
/*
1829-
* this is to avoid deadlock:
1830-
* - lock_page(sum_page) - f2fs_replace_block
1831-
* - check_valid_map() - down_write(sentry_lock)
1832-
* - down_read(sentry_lock) - change_curseg()
1833-
* - lock_page(sum_page)
1834-
*/
1835-
if (type == SUM_TYPE_NODE)
1836-
submitted += gc_node_segment(sbi, sum->entries, segno,
1837-
gc_type);
1838-
else
1839-
submitted += gc_data_segment(sbi, sum->entries, gc_list,
1840-
segno, gc_type,
1841-
force_migrate);
1830+
if (get_valid_blocks(sbi, cur_segno, false) == 0)
1831+
goto freed;
1832+
if (gc_type == BG_GC && __is_large_section(sbi) &&
1833+
migrated >= sbi->migration_granularity)
1834+
continue;
18421835

1843-
stat_inc_gc_seg_count(sbi, data_type, gc_type);
1844-
sbi->gc_reclaimed_segs[sbi->gc_mode]++;
1845-
migrated++;
1836+
sum = SUM_BLK_PAGE_ADDR(sum_folio, cur_segno);
1837+
if (type != GET_SUM_TYPE((&sum->footer))) {
1838+
f2fs_err(sbi, "Inconsistent segment (%u) type "
1839+
"[%d, %d] in SSA and SIT",
1840+
cur_segno, type,
1841+
GET_SUM_TYPE((&sum->footer)));
1842+
f2fs_stop_checkpoint(sbi, false,
1843+
STOP_CP_REASON_CORRUPTED_SUMMARY);
1844+
continue;
1845+
}
18461846

1847-
freed:
1848-
if (gc_type == FG_GC &&
1849-
get_valid_blocks(sbi, segno, false) == 0)
1850-
seg_freed++;
1847+
/*
1848+
* this is to avoid deadlock:
1849+
* - lock_page(sum_page) - f2fs_replace_block
1850+
* - check_valid_map() - down_write(sentry_lock)
1851+
* - down_read(sentry_lock) - change_curseg()
1852+
* - lock_page(sum_page)
1853+
*/
1854+
if (type == SUM_TYPE_NODE)
1855+
submitted += gc_node_segment(sbi, sum->entries,
1856+
cur_segno, gc_type);
1857+
else
1858+
submitted += gc_data_segment(sbi, sum->entries,
1859+
gc_list, cur_segno,
1860+
gc_type, force_migrate);
18511861

1852-
if (__is_large_section(sbi))
1853-
sbi->next_victim_seg[gc_type] =
1854-
(segno + 1 < sec_end_segno) ?
1855-
segno + 1 : NULL_SEGNO;
1856-
skip:
1862+
stat_inc_gc_seg_count(sbi, data_type, gc_type);
1863+
sbi->gc_reclaimed_segs[sbi->gc_mode]++;
1864+
migrated++;
1865+
1866+
freed:
1867+
if (gc_type == FG_GC &&
1868+
get_valid_blocks(sbi, cur_segno, false) == 0)
1869+
seg_freed++;
1870+
1871+
if (__is_large_section(sbi))
1872+
sbi->next_victim_seg[gc_type] =
1873+
(cur_segno + 1 < sec_end_segno) ?
1874+
cur_segno + 1 : NULL_SEGNO;
1875+
}
1876+
next_block:
18571877
folio_put_refs(sum_folio, 2);
1878+
segno = block_end_segno;
18581879
}
18591880

18601881
if (submitted)

fs/f2fs/recovery.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
522522
sum_folio = f2fs_get_sum_folio(sbi, segno);
523523
if (IS_ERR(sum_folio))
524524
return PTR_ERR(sum_folio);
525-
sum_node = folio_address(sum_folio);
525+
sum_node = SUM_BLK_PAGE_ADDR(sum_folio, segno);
526526
sum = sum_node->entries[blkoff];
527527
f2fs_folio_put(sum_folio, true);
528528
got_it:

fs/f2fs/segment.c

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,17 +2712,37 @@ struct folio *f2fs_get_sum_folio(struct f2fs_sb_info *sbi, unsigned int segno)
27122712
void f2fs_update_meta_page(struct f2fs_sb_info *sbi,
27132713
void *src, block_t blk_addr)
27142714
{
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;
27162724

27172725
memcpy(folio_address(folio), src, PAGE_SIZE);
27182726
folio_mark_dirty(folio);
27192727
f2fs_folio_put(folio, true);
27202728
}
27212729

27222730
static void write_sum_page(struct f2fs_sb_info *sbi,
2723-
struct f2fs_summary_block *sum_blk, block_t blk_addr)
2731+
struct f2fs_summary_block *sum_blk, unsigned int segno)
27242732
{
2725-
f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr);
2733+
struct folio *folio;
2734+
2735+
if (SUMS_PER_BLOCK == 1)
2736+
return f2fs_update_meta_page(sbi, (void *)sum_blk,
2737+
GET_SUM_BLOCK(sbi, segno));
2738+
2739+
folio = f2fs_get_sum_folio(sbi, segno);
2740+
if (IS_ERR(folio))
2741+
return;
2742+
2743+
memcpy(SUM_BLK_PAGE_ADDR(folio, segno), sum_blk, sizeof(*sum_blk));
2744+
folio_mark_dirty(folio);
2745+
f2fs_folio_put(folio, true);
27262746
}
27272747

27282748
static void write_current_sum_page(struct f2fs_sb_info *sbi,
@@ -2987,7 +3007,7 @@ static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
29873007
int ret;
29883008

29893009
if (curseg->inited)
2990-
write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, segno));
3010+
write_sum_page(sbi, curseg->sum_blk, segno);
29913011

29923012
segno = __get_next_segno(sbi, type);
29933013
ret = get_new_segment(sbi, &segno, new_sec, pinning);
@@ -3046,7 +3066,7 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type)
30463066
struct folio *sum_folio;
30473067

30483068
if (curseg->inited)
3049-
write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno));
3069+
write_sum_page(sbi, curseg->sum_blk, curseg->segno);
30503070

30513071
__set_test_and_inuse(sbi, new_segno);
30523072

@@ -3065,7 +3085,7 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type)
30653085
memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE);
30663086
return PTR_ERR(sum_folio);
30673087
}
3068-
sum_node = folio_address(sum_folio);
3088+
sum_node = SUM_BLK_PAGE_ADDR(sum_folio, new_segno);
30693089
memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
30703090
f2fs_folio_put(sum_folio, true);
30713091
return 0;
@@ -3154,8 +3174,7 @@ static void __f2fs_save_inmem_curseg(struct f2fs_sb_info *sbi, int type)
31543174
goto out;
31553175

31563176
if (get_valid_blocks(sbi, curseg->segno, false)) {
3157-
write_sum_page(sbi, curseg->sum_blk,
3158-
GET_SUM_BLOCK(sbi, curseg->segno));
3177+
write_sum_page(sbi, curseg->sum_blk, curseg->segno);
31593178
} else {
31603179
mutex_lock(&DIRTY_I(sbi)->seglist_lock);
31613180
__set_test_and_free(sbi, curseg->segno, true);
@@ -3833,8 +3852,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio,
38333852
if (segment_full) {
38343853
if (type == CURSEG_COLD_DATA_PINNED &&
38353854
!((curseg->segno + 1) % sbi->segs_per_sec)) {
3836-
write_sum_page(sbi, curseg->sum_blk,
3837-
GET_SUM_BLOCK(sbi, curseg->segno));
3855+
write_sum_page(sbi, curseg->sum_blk, curseg->segno);
38383856
reset_curseg_fields(curseg);
38393857
goto skip_new_segment;
38403858
}

fs/f2fs/segment.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
8585
#define GET_ZONE_FROM_SEG(sbi, segno) \
8686
GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno))
8787

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)
9094

9195
#define GET_SUM_TYPE(footer) ((footer)->entry_type)
9296
#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type))

fs/f2fs/super.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4080,6 +4080,20 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
40804080
if (sanity_check_area_boundary(sbi, folio, index))
40814081
return -EFSCORRUPTED;
40824082

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+
40834097
return 0;
40844098
}
40854099

fs/f2fs/sysfs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ static ssize_t features_show(struct f2fs_attr *a,
235235
if (f2fs_sb_has_compression(sbi))
236236
len += sysfs_emit_at(buf, len, "%s%s",
237237
len ? ", " : "", "compression");
238+
if (f2fs_sb_has_packed_ssa(sbi))
239+
len += sysfs_emit_at(buf, len, "%s%s",
240+
len ? ", " : "", "packed_ssa");
238241
len += sysfs_emit_at(buf, len, "%s%s",
239242
len ? ", " : "", "pin_file");
240243
len += sysfs_emit_at(buf, len, "\n");
@@ -1296,6 +1299,7 @@ F2FS_FEATURE_RO_ATTR(pin_file);
12961299
#ifdef CONFIG_UNICODE
12971300
F2FS_FEATURE_RO_ATTR(linear_lookup);
12981301
#endif
1302+
F2FS_FEATURE_RO_ATTR(packed_ssa);
12991303

13001304
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
13011305
static struct attribute *f2fs_attrs[] = {
@@ -1455,6 +1459,7 @@ static struct attribute *f2fs_feat_attrs[] = {
14551459
#ifdef CONFIG_UNICODE
14561460
BASE_ATTR_LIST(linear_lookup),
14571461
#endif
1462+
BASE_ATTR_LIST(packed_ssa),
14581463
NULL,
14591464
};
14601465
ATTRIBUTE_GROUPS(f2fs_feat);
@@ -1490,6 +1495,7 @@ F2FS_SB_FEATURE_RO_ATTR(casefold, CASEFOLD);
14901495
F2FS_SB_FEATURE_RO_ATTR(compression, COMPRESSION);
14911496
F2FS_SB_FEATURE_RO_ATTR(readonly, RO);
14921497
F2FS_SB_FEATURE_RO_ATTR(device_alias, DEVICE_ALIAS);
1498+
F2FS_SB_FEATURE_RO_ATTR(packed_ssa, PACKED_SSA);
14931499

14941500
static struct attribute *f2fs_sb_feat_attrs[] = {
14951501
ATTR_LIST(sb_encryption),
@@ -1507,6 +1513,7 @@ static struct attribute *f2fs_sb_feat_attrs[] = {
15071513
ATTR_LIST(sb_compression),
15081514
ATTR_LIST(sb_readonly),
15091515
ATTR_LIST(sb_device_alias),
1516+
ATTR_LIST(sb_packed_ssa),
15101517
NULL,
15111518
};
15121519
ATTRIBUTE_GROUPS(f2fs_sb_feat);

include/linux/f2fs_fs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */
1818
#define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */
1919
#define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */
20+
#define F2FS_SUM_BLKSIZE 4096 /* only support 4096 byte sum block */
2021
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */
2122
#define F2FS_EXTENSION_LEN 8 /* max size of extension */
2223

@@ -441,7 +442,7 @@ struct f2fs_sit_block {
441442
* from node's page's beginning to get a data block address.
442443
* ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node)
443444
*/
444-
#define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8)
445+
#define ENTRIES_IN_SUM (F2FS_SUM_BLKSIZE / 8)
445446
#define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */
446447
#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */
447448
#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM)
@@ -467,7 +468,7 @@ struct summary_footer {
467468
__le32 check_sum; /* summary checksum */
468469
} __packed;
469470

470-
#define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\
471+
#define SUM_JOURNAL_SIZE (F2FS_SUM_BLKSIZE - SUM_FOOTER_SIZE -\
471472
SUM_ENTRY_SIZE)
472473
#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\
473474
sizeof(struct nat_journal_entry))

0 commit comments

Comments
 (0)