f2fs: support non-4KB block size without packed_ssa feature

Currently, F2FS requires the packed_ssa feature to be enabled when
utilizing non-4KB block sizes (e.g., 16KB). This restriction limits
the flexibility of filesystem formatting options.

This patch allows F2FS to support non-4KB block sizes even when the
packed_ssa feature is disabled. It adjusts the SSA calculation logic to
correctly handle summary entries in larger blocks without the packed
layout.

Cc: stable@kernel.org
Fixes: 7ee8bc3942 ("f2fs: revert summary entry count from 2048 to 512 in 16kb block support")
Signed-off-by: Daeho Jeong <daehojeong@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Daeho Jeong 2026-01-10 15:54:05 -08:00 committed by Jaegeuk Kim
parent 1dd3b437d4
commit e48e16f3e3
8 changed files with 165 additions and 122 deletions

View File

@ -545,13 +545,25 @@ struct fsync_inode_entry {
#define nats_in_cursum(jnl) (le16_to_cpu((jnl)->n_nats)) #define nats_in_cursum(jnl) (le16_to_cpu((jnl)->n_nats))
#define sits_in_cursum(jnl) (le16_to_cpu((jnl)->n_sits)) #define sits_in_cursum(jnl) (le16_to_cpu((jnl)->n_sits))
#define nat_in_journal(jnl, i) ((jnl)->nat_j.entries[i].ne) #define nat_in_journal(jnl, i) \
#define nid_in_journal(jnl, i) ((jnl)->nat_j.entries[i].nid) (((struct nat_journal_entry *)(jnl)->nat_j.entries)[i].ne)
#define sit_in_journal(jnl, i) ((jnl)->sit_j.entries[i].se) #define nid_in_journal(jnl, i) \
#define segno_in_journal(jnl, i) ((jnl)->sit_j.entries[i].segno) (((struct nat_journal_entry *)(jnl)->nat_j.entries)[i].nid)
#define sit_in_journal(jnl, i) \
(((struct sit_journal_entry *)(jnl)->sit_j.entries)[i].se)
#define segno_in_journal(jnl, i) \
(((struct sit_journal_entry *)(jnl)->sit_j.entries)[i].segno)
#define MAX_NAT_JENTRIES(jnl) (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl)) #define sum_entries(sum) ((struct f2fs_summary *)(sum))
#define MAX_SIT_JENTRIES(jnl) (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl)) #define sum_journal(sbi, sum) \
((struct f2fs_journal *)((char *)(sum) + \
((sbi)->entries_in_sum * sizeof(struct f2fs_summary))))
#define sum_footer(sbi, sum) \
((struct summary_footer *)((char *)(sum) + (sbi)->sum_blocksize - \
sizeof(struct summary_footer)))
#define MAX_NAT_JENTRIES(sbi, jnl) ((sbi)->nat_journal_entries - nats_in_cursum(jnl))
#define MAX_SIT_JENTRIES(sbi, jnl) ((sbi)->sit_journal_entries - sits_in_cursum(jnl))
static inline int update_nats_in_cursum(struct f2fs_journal *journal, int i) static inline int update_nats_in_cursum(struct f2fs_journal *journal, int i)
{ {
@ -569,14 +581,6 @@ static inline int update_sits_in_cursum(struct f2fs_journal *journal, int i)
return before; return before;
} }
static inline bool __has_cursum_space(struct f2fs_journal *journal,
int size, int type)
{
if (type == NAT_JOURNAL)
return size <= MAX_NAT_JENTRIES(journal);
return size <= MAX_SIT_JENTRIES(journal);
}
/* for inline stuff */ /* for inline stuff */
#define DEF_INLINE_RESERVED_SIZE 1 #define DEF_INLINE_RESERVED_SIZE 1
static inline int get_extra_isize(struct inode *inode); static inline int get_extra_isize(struct inode *inode);
@ -1809,6 +1813,15 @@ struct f2fs_sb_info {
bool readdir_ra; /* readahead inode in readdir */ bool readdir_ra; /* readahead inode in readdir */
unsigned int max_io_bytes; /* max io bytes to merge IOs */ unsigned int max_io_bytes; /* max io bytes to merge IOs */
/* variable summary block units */
unsigned int sum_blocksize; /* sum block size */
unsigned int sums_per_block; /* sum block count per block */
unsigned int entries_in_sum; /* entry count in sum block */
unsigned int sum_entry_size; /* total entry size in sum block */
unsigned int sum_journal_size; /* journal size in sum block */
unsigned int nat_journal_entries; /* nat journal entry count in the journal */
unsigned int sit_journal_entries; /* sit journal entry count in the journal */
block_t user_block_count; /* # of user blocks */ block_t user_block_count; /* # of user blocks */
block_t total_valid_block_count; /* # of valid blocks */ block_t total_valid_block_count; /* # of valid blocks */
block_t discard_blks; /* discard command candidats */ block_t discard_blks; /* discard command candidats */
@ -2850,6 +2863,14 @@ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
} }
static inline bool __has_cursum_space(struct f2fs_sb_info *sbi,
struct f2fs_journal *journal, int size, int type)
{
if (type == NAT_JOURNAL)
return size <= MAX_NAT_JENTRIES(sbi, journal);
return size <= MAX_SIT_JENTRIES(sbi, journal);
}
extern void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync); extern void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync);
static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
struct inode *inode, bool is_inode) struct inode *inode, bool is_inode)
@ -3993,7 +4014,8 @@ void f2fs_wait_on_block_writeback_range(struct inode *inode, block_t blkaddr,
block_t len); block_t len);
void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk); void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk); void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, int f2fs_lookup_journal_in_cursum(struct f2fs_sb_info *sbi,
struct f2fs_journal *journal, int type,
unsigned int val, int alloc); unsigned int val, int alloc);
void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc); void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
int f2fs_check_and_fix_write_pointer(struct f2fs_sb_info *sbi); int f2fs_check_and_fix_write_pointer(struct f2fs_sb_info *sbi);

View File

@ -1782,8 +1782,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type);
segno = rounddown(segno, SUMS_PER_BLOCK); segno = rounddown(segno, sbi->sums_per_block);
sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK); sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, sbi->sums_per_block);
/* readahead multi ssa blocks those have contiguous address */ /* readahead multi ssa blocks those have contiguous address */
if (__is_large_section(sbi)) if (__is_large_section(sbi))
f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
@ -1793,17 +1793,17 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
while (segno < end_segno) { while (segno < end_segno) {
struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno); struct folio *sum_folio = f2fs_get_sum_folio(sbi, segno);
segno += SUMS_PER_BLOCK; segno += sbi->sums_per_block;
if (IS_ERR(sum_folio)) { if (IS_ERR(sum_folio)) {
int err = PTR_ERR(sum_folio); int err = PTR_ERR(sum_folio);
end_segno = segno - SUMS_PER_BLOCK; end_segno = segno - sbi->sums_per_block;
segno = rounddown(start_segno, SUMS_PER_BLOCK); segno = rounddown(start_segno, sbi->sums_per_block);
while (segno < end_segno) { while (segno < end_segno) {
sum_folio = filemap_get_folio(META_MAPPING(sbi), sum_folio = filemap_get_folio(META_MAPPING(sbi),
GET_SUM_BLOCK(sbi, segno)); GET_SUM_BLOCK(sbi, segno));
folio_put_refs(sum_folio, 2); folio_put_refs(sum_folio, 2);
segno += SUMS_PER_BLOCK; segno += sbi->sums_per_block;
} }
return err; return err;
} }
@ -1819,8 +1819,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
/* find segment summary of victim */ /* find segment summary of victim */
struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi), struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi),
GET_SUM_BLOCK(sbi, segno)); GET_SUM_BLOCK(sbi, segno));
unsigned int block_end_segno = rounddown(segno, SUMS_PER_BLOCK) unsigned int block_end_segno = rounddown(segno, sbi->sums_per_block)
+ SUMS_PER_BLOCK; + sbi->sums_per_block;
if (block_end_segno > end_segno) if (block_end_segno > end_segno)
block_end_segno = end_segno; block_end_segno = end_segno;
@ -1846,12 +1846,13 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
migrated >= sbi->migration_granularity) migrated >= sbi->migration_granularity)
continue; continue;
sum = SUM_BLK_PAGE_ADDR(sum_folio, cur_segno); sum = SUM_BLK_PAGE_ADDR(sbi, sum_folio, cur_segno);
if (type != GET_SUM_TYPE((&sum->footer))) { if (type != GET_SUM_TYPE(sum_footer(sbi, sum))) {
f2fs_err(sbi, "Inconsistent segment (%u) type " f2fs_err(sbi, "Inconsistent segment (%u) type "
"[%d, %d] in SSA and SIT", "[%d, %d] in SSA and SIT",
cur_segno, type, cur_segno, type,
GET_SUM_TYPE((&sum->footer))); GET_SUM_TYPE(
sum_footer(sbi, sum)));
f2fs_stop_checkpoint(sbi, false, f2fs_stop_checkpoint(sbi, false,
STOP_CP_REASON_CORRUPTED_SUMMARY); STOP_CP_REASON_CORRUPTED_SUMMARY);
continue; continue;

View File

@ -606,7 +606,7 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
goto retry; goto retry;
} }
i = f2fs_lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0); i = f2fs_lookup_journal_in_cursum(sbi, journal, NAT_JOURNAL, nid, 0);
if (i >= 0) { if (i >= 0) {
ne = nat_in_journal(journal, i); ne = nat_in_journal(journal, i);
node_info_from_raw_nat(ni, &ne); node_info_from_raw_nat(ni, &ne);
@ -2955,7 +2955,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
/* scan the node segment */ /* scan the node segment */
last_offset = BLKS_PER_SEG(sbi); last_offset = BLKS_PER_SEG(sbi);
addr = START_BLOCK(sbi, segno); addr = START_BLOCK(sbi, segno);
sum_entry = &sum->entries[0]; sum_entry = sum_entries(sum);
for (i = 0; i < last_offset; i += nrpages, addr += nrpages) { for (i = 0; i < last_offset; i += nrpages, addr += nrpages) {
nrpages = bio_max_segs(last_offset - i); nrpages = bio_max_segs(last_offset - i);
@ -3096,7 +3096,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
* #2, flush nat entries to nat page. * #2, flush nat entries to nat page.
*/ */
if (enabled_nat_bits(sbi, cpc) || if (enabled_nat_bits(sbi, cpc) ||
!__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL)) !__has_cursum_space(sbi, journal, set->entry_cnt, NAT_JOURNAL))
to_journal = false; to_journal = false;
if (to_journal) { if (to_journal) {
@ -3119,7 +3119,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR); f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR);
if (to_journal) { if (to_journal) {
offset = f2fs_lookup_journal_in_cursum(journal, offset = f2fs_lookup_journal_in_cursum(sbi, journal,
NAT_JOURNAL, nid, 1); NAT_JOURNAL, nid, 1);
f2fs_bug_on(sbi, offset < 0); f2fs_bug_on(sbi, offset < 0);
raw_ne = &nat_in_journal(journal, offset); raw_ne = &nat_in_journal(journal, offset);
@ -3190,7 +3190,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
* into nat entry set. * into nat entry set.
*/ */
if (enabled_nat_bits(sbi, cpc) || if (enabled_nat_bits(sbi, cpc) ||
!__has_cursum_space(journal, !__has_cursum_space(sbi, journal,
nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL)) nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))
remove_nats_in_journal(sbi); remove_nats_in_journal(sbi);
@ -3201,7 +3201,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
set_idx = setvec[found - 1]->set + 1; set_idx = setvec[found - 1]->set + 1;
for (idx = 0; idx < found; idx++) for (idx = 0; idx < found; idx++)
__adjust_nat_entry_set(setvec[idx], &sets, __adjust_nat_entry_set(setvec[idx], &sets,
MAX_NAT_JENTRIES(journal)); MAX_NAT_JENTRIES(sbi, journal));
} }
/* flush dirty nats in nat entry set */ /* flush dirty nats in nat entry set */

View File

@ -514,7 +514,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
struct curseg_info *curseg = CURSEG_I(sbi, i); struct curseg_info *curseg = CURSEG_I(sbi, i);
if (curseg->segno == segno) { if (curseg->segno == segno) {
sum = curseg->sum_blk->entries[blkoff]; sum = sum_entries(curseg->sum_blk)[blkoff];
goto got_it; goto got_it;
} }
} }
@ -522,8 +522,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
sum_folio = f2fs_get_sum_folio(sbi, segno); sum_folio = f2fs_get_sum_folio(sbi, segno);
if (IS_ERR(sum_folio)) if (IS_ERR(sum_folio))
return PTR_ERR(sum_folio); return PTR_ERR(sum_folio);
sum_node = SUM_BLK_PAGE_ADDR(sum_folio, segno); sum_node = SUM_BLK_PAGE_ADDR(sbi, sum_folio, segno);
sum = sum_node->entries[blkoff]; sum = sum_entries(sum_node)[blkoff];
f2fs_folio_put(sum_folio, true); f2fs_folio_put(sum_folio, true);
got_it: got_it:
/* Use the locked dnode page and inode */ /* Use the locked dnode page and inode */

View File

@ -2674,12 +2674,12 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
valid_sum_count += f2fs_curseg_valid_blocks(sbi, i); valid_sum_count += f2fs_curseg_valid_blocks(sbi, i);
} }
sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - sum_in_page = (sbi->sum_blocksize - 2 * sbi->sum_journal_size -
SUM_FOOTER_SIZE) / SUMMARY_SIZE; SUM_FOOTER_SIZE) / SUMMARY_SIZE;
if (valid_sum_count <= sum_in_page) if (valid_sum_count <= sum_in_page)
return 1; return 1;
else if ((valid_sum_count - sum_in_page) <= else if ((valid_sum_count - sum_in_page) <=
(PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) (sbi->sum_blocksize - SUM_FOOTER_SIZE) / SUMMARY_SIZE)
return 2; return 2;
return 3; return 3;
} }
@ -2699,7 +2699,7 @@ void f2fs_update_meta_page(struct f2fs_sb_info *sbi,
{ {
struct folio *folio; struct folio *folio;
if (SUMS_PER_BLOCK == 1) if (!f2fs_sb_has_packed_ssa(sbi))
folio = f2fs_grab_meta_folio(sbi, blk_addr); folio = f2fs_grab_meta_folio(sbi, blk_addr);
else else
folio = f2fs_get_meta_folio_retry(sbi, blk_addr); folio = f2fs_get_meta_folio_retry(sbi, blk_addr);
@ -2717,7 +2717,7 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
{ {
struct folio *folio; struct folio *folio;
if (SUMS_PER_BLOCK == 1) if (!f2fs_sb_has_packed_ssa(sbi))
return f2fs_update_meta_page(sbi, (void *)sum_blk, return f2fs_update_meta_page(sbi, (void *)sum_blk,
GET_SUM_BLOCK(sbi, segno)); GET_SUM_BLOCK(sbi, segno));
@ -2725,7 +2725,8 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
if (IS_ERR(folio)) if (IS_ERR(folio))
return; return;
memcpy(SUM_BLK_PAGE_ADDR(folio, segno), sum_blk, sizeof(*sum_blk)); memcpy(SUM_BLK_PAGE_ADDR(sbi, folio, segno), sum_blk,
sbi->sum_blocksize);
folio_mark_dirty(folio); folio_mark_dirty(folio);
f2fs_folio_put(folio, true); f2fs_folio_put(folio, true);
} }
@ -2744,11 +2745,11 @@ static void write_current_sum_page(struct f2fs_sb_info *sbi,
mutex_lock(&curseg->curseg_mutex); mutex_lock(&curseg->curseg_mutex);
down_read(&curseg->journal_rwsem); down_read(&curseg->journal_rwsem);
memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE); memcpy(sum_journal(sbi, dst), curseg->journal, sbi->sum_journal_size);
up_read(&curseg->journal_rwsem); up_read(&curseg->journal_rwsem);
memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); memcpy(sum_entries(dst), sum_entries(src), sbi->sum_entry_size);
memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); memcpy(sum_footer(sbi, dst), sum_footer(sbi, src), SUM_FOOTER_SIZE);
mutex_unlock(&curseg->curseg_mutex); mutex_unlock(&curseg->curseg_mutex);
@ -2921,7 +2922,7 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
curseg->next_blkoff = 0; curseg->next_blkoff = 0;
curseg->next_segno = NULL_SEGNO; curseg->next_segno = NULL_SEGNO;
sum_footer = &(curseg->sum_blk->footer); sum_footer = sum_footer(sbi, curseg->sum_blk);
memset(sum_footer, 0, sizeof(struct summary_footer)); memset(sum_footer, 0, sizeof(struct summary_footer));
sanity_check_seg_type(sbi, seg_type); sanity_check_seg_type(sbi, seg_type);
@ -3067,11 +3068,11 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type)
sum_folio = f2fs_get_sum_folio(sbi, new_segno); sum_folio = f2fs_get_sum_folio(sbi, new_segno);
if (IS_ERR(sum_folio)) { if (IS_ERR(sum_folio)) {
/* GC won't be able to use stale summary pages by cp_error */ /* GC won't be able to use stale summary pages by cp_error */
memset(curseg->sum_blk, 0, SUM_ENTRY_SIZE); memset(curseg->sum_blk, 0, sbi->sum_entry_size);
return PTR_ERR(sum_folio); return PTR_ERR(sum_folio);
} }
sum_node = SUM_BLK_PAGE_ADDR(sum_folio, new_segno); sum_node = SUM_BLK_PAGE_ADDR(sbi, sum_folio, new_segno);
memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); memcpy(curseg->sum_blk, sum_node, sbi->sum_entry_size);
f2fs_folio_put(sum_folio, true); f2fs_folio_put(sum_folio, true);
return 0; return 0;
} }
@ -3805,7 +3806,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct folio *folio,
f2fs_wait_discard_bio(sbi, *new_blkaddr); f2fs_wait_discard_bio(sbi, *new_blkaddr);
curseg->sum_blk->entries[curseg->next_blkoff] = *sum; sum_entries(curseg->sum_blk)[curseg->next_blkoff] = *sum;
if (curseg->alloc_type == SSR) { if (curseg->alloc_type == SSR) {
curseg->next_blkoff = f2fs_find_next_ssr_block(sbi, curseg); curseg->next_blkoff = f2fs_find_next_ssr_block(sbi, curseg);
} else { } else {
@ -4174,7 +4175,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
} }
curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
curseg->sum_blk->entries[curseg->next_blkoff] = *sum; sum_entries(curseg->sum_blk)[curseg->next_blkoff] = *sum;
if (!recover_curseg || recover_newaddr) { if (!recover_curseg || recover_newaddr) {
if (!from_gc) if (!from_gc)
@ -4294,12 +4295,12 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
/* Step 1: restore nat cache */ /* Step 1: restore nat cache */
seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE); memcpy(seg_i->journal, kaddr, sbi->sum_journal_size);
/* Step 2: restore sit cache */ /* Step 2: restore sit cache */
seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); memcpy(seg_i->journal, kaddr + sbi->sum_journal_size, sbi->sum_journal_size);
offset = 2 * SUM_JOURNAL_SIZE; offset = 2 * sbi->sum_journal_size;
/* Step 3: restore summary entries */ /* Step 3: restore summary entries */
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
@ -4321,9 +4322,9 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
struct f2fs_summary *s; struct f2fs_summary *s;
s = (struct f2fs_summary *)(kaddr + offset); s = (struct f2fs_summary *)(kaddr + offset);
seg_i->sum_blk->entries[j] = *s; sum_entries(seg_i->sum_blk)[j] = *s;
offset += SUMMARY_SIZE; offset += SUMMARY_SIZE;
if (offset + SUMMARY_SIZE <= PAGE_SIZE - if (offset + SUMMARY_SIZE <= sbi->sum_blocksize -
SUM_FOOTER_SIZE) SUM_FOOTER_SIZE)
continue; continue;
@ -4379,7 +4380,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
if (IS_NODESEG(type)) { if (IS_NODESEG(type)) {
if (__exist_node_summaries(sbi)) { if (__exist_node_summaries(sbi)) {
struct f2fs_summary *ns = &sum->entries[0]; struct f2fs_summary *ns = sum_entries(sum);
int i; int i;
for (i = 0; i < BLKS_PER_SEG(sbi); i++, ns++) { for (i = 0; i < BLKS_PER_SEG(sbi); i++, ns++) {
@ -4399,11 +4400,13 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
/* update journal info */ /* update journal info */
down_write(&curseg->journal_rwsem); down_write(&curseg->journal_rwsem);
memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE); memcpy(curseg->journal, sum_journal(sbi, sum), sbi->sum_journal_size);
up_write(&curseg->journal_rwsem); up_write(&curseg->journal_rwsem);
memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE); memcpy(sum_entries(curseg->sum_blk), sum_entries(sum),
memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE); sbi->sum_entry_size);
memcpy(sum_footer(sbi, curseg->sum_blk), sum_footer(sbi, sum),
SUM_FOOTER_SIZE);
curseg->next_segno = segno; curseg->next_segno = segno;
reset_curseg(sbi, type, 0); reset_curseg(sbi, type, 0);
curseg->alloc_type = ckpt->alloc_type[type]; curseg->alloc_type = ckpt->alloc_type[type];
@ -4447,8 +4450,8 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
} }
/* sanity check for summary blocks */ /* sanity check for summary blocks */
if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || if (nats_in_cursum(nat_j) > sbi->nat_journal_entries ||
sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) { sits_in_cursum(sit_j) > sbi->sit_journal_entries) {
f2fs_err(sbi, "invalid journal entries nats %u sits %u", f2fs_err(sbi, "invalid journal entries nats %u sits %u",
nats_in_cursum(nat_j), sits_in_cursum(sit_j)); nats_in_cursum(nat_j), sits_in_cursum(sit_j));
return -EINVAL; return -EINVAL;
@ -4472,13 +4475,13 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
/* Step 1: write nat cache */ /* Step 1: write nat cache */
seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); memcpy(kaddr, seg_i->journal, sbi->sum_journal_size);
written_size += SUM_JOURNAL_SIZE; written_size += sbi->sum_journal_size;
/* Step 2: write sit cache */ /* Step 2: write sit cache */
seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); memcpy(kaddr + written_size, seg_i->journal, sbi->sum_journal_size);
written_size += SUM_JOURNAL_SIZE; written_size += sbi->sum_journal_size;
/* Step 3: write summary entries */ /* Step 3: write summary entries */
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
@ -4491,7 +4494,7 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
written_size = 0; written_size = 0;
} }
summary = (struct f2fs_summary *)(kaddr + written_size); summary = (struct f2fs_summary *)(kaddr + written_size);
*summary = seg_i->sum_blk->entries[j]; *summary = sum_entries(seg_i->sum_blk)[j];
written_size += SUMMARY_SIZE; written_size += SUMMARY_SIZE;
if (written_size + SUMMARY_SIZE <= PAGE_SIZE - if (written_size + SUMMARY_SIZE <= PAGE_SIZE -
@ -4536,7 +4539,8 @@ void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
} }
int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, int f2fs_lookup_journal_in_cursum(struct f2fs_sb_info *sbi,
struct f2fs_journal *journal, int type,
unsigned int val, int alloc) unsigned int val, int alloc)
{ {
int i; int i;
@ -4546,13 +4550,13 @@ int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
if (le32_to_cpu(nid_in_journal(journal, i)) == val) if (le32_to_cpu(nid_in_journal(journal, i)) == val)
return i; return i;
} }
if (alloc && __has_cursum_space(journal, 1, NAT_JOURNAL)) if (alloc && __has_cursum_space(sbi, journal, 1, NAT_JOURNAL))
return update_nats_in_cursum(journal, 1); return update_nats_in_cursum(journal, 1);
} else if (type == SIT_JOURNAL) { } else if (type == SIT_JOURNAL) {
for (i = 0; i < sits_in_cursum(journal); i++) for (i = 0; i < sits_in_cursum(journal); i++)
if (le32_to_cpu(segno_in_journal(journal, i)) == val) if (le32_to_cpu(segno_in_journal(journal, i)) == val)
return i; return i;
if (alloc && __has_cursum_space(journal, 1, SIT_JOURNAL)) if (alloc && __has_cursum_space(sbi, journal, 1, SIT_JOURNAL))
return update_sits_in_cursum(journal, 1); return update_sits_in_cursum(journal, 1);
} }
return -1; return -1;
@ -4700,8 +4704,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
* entries, remove all entries from journal and add and account * entries, remove all entries from journal and add and account
* them in sit entry set. * them in sit entry set.
*/ */
if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) || if (!__has_cursum_space(sbi, journal,
!to_journal) sit_i->dirty_sentries, SIT_JOURNAL) || !to_journal)
remove_sits_in_journal(sbi); remove_sits_in_journal(sbi);
/* /*
@ -4718,7 +4722,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
unsigned int segno = start_segno; unsigned int segno = start_segno;
if (to_journal && if (to_journal &&
!__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL)) !__has_cursum_space(sbi, journal, ses->entry_cnt,
SIT_JOURNAL))
to_journal = false; to_journal = false;
if (to_journal) { if (to_journal) {
@ -4746,7 +4751,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
} }
if (to_journal) { if (to_journal) {
offset = f2fs_lookup_journal_in_cursum(journal, offset = f2fs_lookup_journal_in_cursum(sbi, journal,
SIT_JOURNAL, segno, 1); SIT_JOURNAL, segno, 1);
f2fs_bug_on(sbi, offset < 0); f2fs_bug_on(sbi, offset < 0);
segno_in_journal(journal, offset) = segno_in_journal(journal, offset) =
@ -4953,12 +4958,13 @@ static int build_curseg(struct f2fs_sb_info *sbi)
for (i = 0; i < NO_CHECK_TYPE; i++) { for (i = 0; i < NO_CHECK_TYPE; i++) {
mutex_init(&array[i].curseg_mutex); mutex_init(&array[i].curseg_mutex);
array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL); array[i].sum_blk = f2fs_kzalloc(sbi, sbi->sum_blocksize,
GFP_KERNEL);
if (!array[i].sum_blk) if (!array[i].sum_blk)
return -ENOMEM; return -ENOMEM;
init_rwsem(&array[i].journal_rwsem); init_rwsem(&array[i].journal_rwsem);
array[i].journal = f2fs_kzalloc(sbi, array[i].journal = f2fs_kzalloc(sbi,
sizeof(struct f2fs_journal), GFP_KERNEL); sbi->sum_journal_size, GFP_KERNEL);
if (!array[i].journal) if (!array[i].journal)
return -ENOMEM; return -ENOMEM;
array[i].seg_type = log_type_to_seg_type(i); array[i].seg_type = log_type_to_seg_type(i);

View File

@ -90,12 +90,11 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
#define GET_ZONE_FROM_SEG(sbi, segno) \ #define GET_ZONE_FROM_SEG(sbi, segno) \
GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno)) GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno))
#define SUMS_PER_BLOCK (F2FS_BLKSIZE / F2FS_SUM_BLKSIZE)
#define GET_SUM_BLOCK(sbi, segno) \ #define GET_SUM_BLOCK(sbi, segno) \
(SM_I(sbi)->ssa_blkaddr + (segno / SUMS_PER_BLOCK)) (SM_I(sbi)->ssa_blkaddr + (segno / (sbi)->sums_per_block))
#define GET_SUM_BLKOFF(segno) (segno % SUMS_PER_BLOCK) #define GET_SUM_BLKOFF(sbi, segno) (segno % (sbi)->sums_per_block)
#define SUM_BLK_PAGE_ADDR(folio, segno) \ #define SUM_BLK_PAGE_ADDR(sbi, folio, segno) \
(folio_address(folio) + GET_SUM_BLKOFF(segno) * F2FS_SUM_BLKSIZE) (folio_address(folio) + GET_SUM_BLKOFF(sbi, segno) * (sbi)->sum_blocksize)
#define GET_SUM_TYPE(footer) ((footer)->entry_type) #define GET_SUM_TYPE(footer) ((footer)->entry_type)
#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type)) #define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type))

View File

@ -4104,20 +4104,6 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
if (sanity_check_area_boundary(sbi, folio, index)) if (sanity_check_area_boundary(sbi, folio, index))
return -EFSCORRUPTED; return -EFSCORRUPTED;
/*
* Check for legacy summary layout on 16KB+ block devices.
* Modern f2fs-tools packs multiple 4KB summary areas into one block,
* whereas legacy versions used one block per summary, leading
* to a much larger SSA.
*/
if (SUMS_PER_BLOCK > 1 &&
!(__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_PACKED_SSA))) {
f2fs_info(sbi, "Error: Device formatted with a legacy version. "
"Please reformat with a tool supporting the packed ssa "
"feature for block sizes larger than 4kb.");
return -EOPNOTSUPP;
}
return 0; return 0;
} }
@ -4329,6 +4315,18 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
atomic64_set(&sbi->current_atomic_write, 0); atomic64_set(&sbi->current_atomic_write, 0);
sbi->max_lock_elapsed_time = MAX_LOCK_ELAPSED_TIME; sbi->max_lock_elapsed_time = MAX_LOCK_ELAPSED_TIME;
sbi->sum_blocksize = f2fs_sb_has_packed_ssa(sbi) ?
4096 : sbi->blocksize;
sbi->sums_per_block = sbi->blocksize / sbi->sum_blocksize;
sbi->entries_in_sum = sbi->sum_blocksize / 8;
sbi->sum_entry_size = SUMMARY_SIZE * sbi->entries_in_sum;
sbi->sum_journal_size = sbi->sum_blocksize - SUM_FOOTER_SIZE -
sbi->sum_entry_size;
sbi->nat_journal_entries = (sbi->sum_journal_size - 2) /
sizeof(struct nat_journal_entry);
sbi->sit_journal_entries = (sbi->sum_journal_size - 2) /
sizeof(struct sit_journal_entry);
sbi->dir_level = DEF_DIR_LEVEL; sbi->dir_level = DEF_DIR_LEVEL;
sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL;

View File

@ -17,7 +17,6 @@
#define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */ #define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sector/blk */
#define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */ #define F2FS_BLKSIZE PAGE_SIZE /* support only block == page */
#define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */ #define F2FS_BLKSIZE_BITS PAGE_SHIFT /* bits for F2FS_BLKSIZE */
#define F2FS_SUM_BLKSIZE 4096 /* only support 4096 byte sum block */
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */
#define F2FS_EXTENSION_LEN 8 /* max size of extension */ #define F2FS_EXTENSION_LEN 8 /* max size of extension */
@ -442,10 +441,8 @@ struct f2fs_sit_block {
* from node's page's beginning to get a data block address. * from node's page's beginning to get a data block address.
* ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node)
*/ */
#define ENTRIES_IN_SUM (F2FS_SUM_BLKSIZE / 8)
#define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */ #define SUMMARY_SIZE (7) /* sizeof(struct f2fs_summary) */
#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ #define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */
#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM)
/* a summary entry for a block in a segment */ /* a summary entry for a block in a segment */
struct f2fs_summary { struct f2fs_summary {
@ -468,22 +465,6 @@ struct summary_footer {
__le32 check_sum; /* summary checksum */ __le32 check_sum; /* summary checksum */
} __packed; } __packed;
#define SUM_JOURNAL_SIZE (F2FS_SUM_BLKSIZE - SUM_FOOTER_SIZE -\
SUM_ENTRY_SIZE)
#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\
sizeof(struct nat_journal_entry))
#define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\
sizeof(struct nat_journal_entry))
#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\
sizeof(struct sit_journal_entry))
#define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\
sizeof(struct sit_journal_entry))
/* Reserved area should make size of f2fs_extra_info equals to
* that of nat_journal and sit_journal.
*/
#define EXTRA_INFO_RESERVED (SUM_JOURNAL_SIZE - 2 - 8)
/* /*
* frequently updated NAT/SIT entries can be stored in the spare area in * frequently updated NAT/SIT entries can be stored in the spare area in
* summary blocks * summary blocks
@ -498,9 +479,16 @@ struct nat_journal_entry {
struct f2fs_nat_entry ne; struct f2fs_nat_entry ne;
} __packed; } __packed;
/*
* The nat_journal structure is a placeholder whose actual size varies depending
* on the use of packed_ssa. Therefore, it must always be accessed only through
* specific sets of macros and fields, and size calculations should use
* size-related macros instead of sizeof().
* Relevant macros: sbi->nat_journal_entries, nat_in_journal(),
* nid_in_journal(), MAX_NAT_JENTRIES().
*/
struct nat_journal { struct nat_journal {
struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; struct nat_journal_entry entries[0];
__u8 reserved[NAT_JOURNAL_RESERVED];
} __packed; } __packed;
struct sit_journal_entry { struct sit_journal_entry {
@ -508,14 +496,21 @@ struct sit_journal_entry {
struct f2fs_sit_entry se; struct f2fs_sit_entry se;
} __packed; } __packed;
/*
* The sit_journal structure is a placeholder whose actual size varies depending
* on the use of packed_ssa. Therefore, it must always be accessed only through
* specific sets of macros and fields, and size calculations should use
* size-related macros instead of sizeof().
* Relevant macros: sbi->sit_journal_entries, sit_in_journal(),
* segno_in_journal(), MAX_SIT_JENTRIES().
*/
struct sit_journal { struct sit_journal {
struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; struct sit_journal_entry entries[0];
__u8 reserved[SIT_JOURNAL_RESERVED];
} __packed; } __packed;
struct f2fs_extra_info { struct f2fs_extra_info {
__le64 kbytes_written; __le64 kbytes_written;
__u8 reserved[EXTRA_INFO_RESERVED]; __u8 reserved[];
} __packed; } __packed;
struct f2fs_journal { struct f2fs_journal {
@ -531,11 +526,33 @@ struct f2fs_journal {
}; };
} __packed; } __packed;
/* Block-sized summary block structure */ /*
* Block-sized summary block structure
*
* The f2fs_summary_block structure is a placeholder whose actual size varies
* depending on the use of packed_ssa. Therefore, it must always be accessed
* only through specific sets of macros and fields, and size calculations should
* use size-related macros instead of sizeof().
* Relevant macros: sbi->sum_blocksize, sbi->entries_in_sum,
* sbi->sum_entry_size, sum_entries(), sum_journal(), sum_footer().
*
* Summary Block Layout
*
* +-----------------------+ <--- Block Start
* | struct f2fs_summary |
* | entries[0] |
* | ... |
* | entries[N-1] |
* +-----------------------+
* | struct f2fs_journal |
* +-----------------------+
* | struct summary_footer |
* +-----------------------+ <--- Block End
*/
struct f2fs_summary_block { struct f2fs_summary_block {
struct f2fs_summary entries[ENTRIES_IN_SUM]; struct f2fs_summary entries[0];
struct f2fs_journal journal; // struct f2fs_journal journal;
struct summary_footer footer; // struct summary_footer footer;
} __packed; } __packed;
/* /*