From nobody Sun Feb 8 10:16:46 2026 Received: from mail-dy1-f171.google.com (mail-dy1-f171.google.com [74.125.82.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A029678F3E for ; Fri, 9 Jan 2026 21:49:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767995350; cv=none; b=E4tPqjb48IC4kxKcr8ug8vC2Sbu6RahPFOAOEvehJHTy2yFu28dLwloI0nMoORiIo7VzkZf3ZB+sj5hLD+CZZdZTHM7Og/ANQzmEIfkyiY7EbcJxGi+VcnSkhr17rR+y52eYoW7MRC31fjpAULhAe6SpiItMELFP3l33gzznvC8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767995350; c=relaxed/simple; bh=jC+br5Eaj8u/hZgboBkzcptshXw7FCl+V57iZRjlzlU=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=tnyUM5oSOBm4wYpE2C/RNQJ4PZMqLFzZSJ5vAmqPhCy3qI9NPhuNVgyFRzqfvuSvkyl/4CD1pnlsUHg0LLZVmtNnhZXu9SLmycOoHfYzvlNPmyqMW0uJtGdcuMb/EaU5SzrfZUqQmQzlyq2lQWBYp09Xa82LTsqCKIaExnJkzBc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=E5rpWfDt; arc=none smtp.client-ip=74.125.82.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="E5rpWfDt" Received: by mail-dy1-f171.google.com with SMTP id 5a478bee46e88-2ae255ac8bdso6623346eec.0 for ; Fri, 09 Jan 2026 13:49:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767995347; x=1768600147; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=xzKLGYhNt6IA5c368cQZbJdEqvWnpICViHK4Q/tfMek=; b=E5rpWfDtuRd8zV1R6mdb4CcMIvOBFQoCC6d6wsARB5NdcNU0uPir9NGB5VmB3qaiUH iH7Hfq+dtVvX1pvSwMHFU6BgY9RIWbNdMtZMSAeH0MSaHtxswyZZVi2KhnDLHB3GW7R0 C/gg0OdUpLVJCG82srnqwL/uxB08wnvIzZiQLRSFCdIHbHJ9KbNs6jH8Xzqsxn2iUI15 3ECVTt+12y2kfZaQ7zMqUHtzJhZkM9Np7wCSI8NXzRyageDKvG7713XLkGw4KCmrc35d 0c6Mnl3ZP19JEjiH6mg2LbFP10jk9PlTaO5JFaRXw/VttcSO1iSiWRJpbfLKLMzRyKbp 99Cw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767995347; x=1768600147; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xzKLGYhNt6IA5c368cQZbJdEqvWnpICViHK4Q/tfMek=; b=N7IRg5Xt7uuG1EDhiTsK7pacy4TbbvJd03xehkod7iQRKJEcpZ57Z1L98Cn4ECadyC zZkae1PgODPYc/o/QD5SznNQts7ffcLwPybTEa+3dZcmCO2nGZ4NbTUFHvUpEbk1EGTP 0s+T5v9EsKK32dbr2z38Lm+actIeISnUg+iQcXe5bfNygYKoAD0gBi0dfxTc+wC9gCk5 TjRGnIjIEuhuHfDXU+9OcAEJfdiIiMtVMVd7WsCL/YiB6JWuAx7xWyf9m1cdkTEGr+zm V1zY7i16bEfhpip8QBCF4mbDVk77XlYlWcWPve15jTEwfNFCdTpqG6s7OmNWgeENBRNe QI5Q== X-Gm-Message-State: AOJu0Ywl9nf4I69E/jRKYlt5MvvFEw91G0nXEazvGynWc0m9TSK1mBzu yh+0qXd0OeeikzTkMpFXddBqneTE2nyRevXnQr39xwCHStKwCO+JM2JirE+rmg== X-Gm-Gg: AY/fxX4sNJmC/h2NCVHDfOVa7AdjFIp483pn0MzsofvaVqY3ht61eAMJx2NXzLd21Sj mBHNfzBY+VDpSU8OgmoRlqCmdDSQe6KNoOVfqncOb1uLbegCkxufBMHFy7zoiFdgEBEvqOUdAmr yUzEOUS9uim9yoUE8+bV8vdh+YBKQmWprKR4IOdqfqTFcvDbmZwY04HnDZXFez7Dpa5+I3zqxl8 A+A1ged7aSx6JSR3tgP1HUOZld7iYWO4AqnEFXGQFugBG6fleoF1We99kMKXA7Hz1ueVrQAR94o QVxHwBxnAHo3JblrvMvd2C0ODFICUZkUGzQnQn/8p0NsFo21DND7iqINXUnDEiwCOK6QeMjEfaN O2fkZjX4neZWuyZc23pGHJEM5C3hPDCXx86H51nxapFW+uhdHo0MrBV+Mzvfflo1VSRYKweZ3kS OhRFy2iC26YIwIQsJozB54RAP5yKvm7zq4s2nTW3STIZ4Jps1mxbo7at+G1fkDMMGSaeehqYeGH dtfJnlALNXSVdETbUeitX5GbqvUb4iBh1BnHg== X-Google-Smtp-Source: AGHT+IF+Ix8XmTUxRt3lABPwK5enrlRjNKx4rVKlGowKkdA2BMbLpv1ghwYVtkPh379c0PbN3OkYYw== X-Received: by 2002:a05:7301:fa0f:b0:2ae:5d8a:7095 with SMTP id 5a478bee46e88-2b17d240a1dmr7932513eec.10.1767995346907; Fri, 09 Jan 2026 13:49:06 -0800 (PST) Received: from daehojeong-desktop.mtv.corp.google.com ([2a00:79e0:2e7c:8:8805:a3e1:e0b:45eb]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2b1775fe27dsm9630644eec.29.2026.01.09.13.49.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 13:49:06 -0800 (PST) From: Daeho Jeong To: linux-kernel@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, kernel-team@android.com Cc: Daeho Jeong Subject: [PATCH v2] f2fs: support non-4KB block size without packed_ssa feature Date: Fri, 9 Jan 2026 13:49:00 -0800 Message-ID: <20260109214900.2134722-1-daeho43@gmail.com> X-Mailer: git-send-email 2.52.0.457.g6b5491de43-goog Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Daeho Jeong 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. Fixes: 7ee8bc3942f2 ("f2fs: revert summary entry count from 2048 to 512 in = 16kb block support") Signed-off-by: Daeho Jeong --- v2: using sbi->sum_blocksize instead of F2FS_SUM_BLKSIZE() --- fs/f2fs/f2fs.h | 55 ++++++++++++++++++-------- fs/f2fs/gc.c | 23 +++++------ fs/f2fs/node.c | 12 +++--- fs/f2fs/recovery.c | 6 +-- fs/f2fs/segment.c | 86 ++++++++++++++++++++++------------------- fs/f2fs/segment.h | 10 ++--- fs/f2fs/super.c | 16 +------- include/linux/f2fs_fs.h | 73 ++++++++++++++++++++-------------- 8 files changed, 158 insertions(+), 123 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 20edbb99b814..cff32c6dbb02 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -521,13 +521,34 @@ struct fsync_inode_entry { #define nats_in_cursum(jnl) (le16_to_cpu((jnl)->n_nats)) #define sits_in_cursum(jnl) (le16_to_cpu((jnl)->n_sits)) =20 -#define nat_in_journal(jnl, i) ((jnl)->nat_j.entries[i].ne) -#define nid_in_journal(jnl, i) ((jnl)->nat_j.entries[i].nid) -#define sit_in_journal(jnl, i) ((jnl)->sit_j.entries[i].se) -#define segno_in_journal(jnl, i) ((jnl)->sit_j.entries[i].segno) - -#define MAX_NAT_JENTRIES(jnl) (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl)) -#define MAX_SIT_JENTRIES(jnl) (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl)) +#define nat_in_journal(jnl, i) \ + (((struct nat_journal_entry *)(jnl)->nat_j.entries)[i].ne) +#define nid_in_journal(jnl, i) \ + (((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 ENTRIES_IN_SUM(sbi) ((sbi)->sum_blocksize / 8) +#define SUM_ENTRY_SIZE(sbi) (SUMMARY_SIZE * ENTRIES_IN_SUM(sbi)) +#define SUM_JOURNAL_SIZE(sbi) ((sbi)->sum_blocksize - SUM_FOOTER_SIZE - \ + SUM_ENTRY_SIZE(sbi)) +#define NAT_JOURNAL_ENTRIES(sbi) ((SUM_JOURNAL_SIZE(sbi) - 2) / \ + sizeof(struct nat_journal_entry)) +#define SIT_JOURNAL_ENTRIES(sbi) ((SUM_JOURNAL_SIZE(sbi) - 2) / \ + sizeof(struct sit_journal_entry)) + +#define sum_entries(sum) ((struct f2fs_summary *)(sum)) +#define sum_journal(sbi, sum) \ + ((struct f2fs_journal *)((char *)(sum) + \ + (ENTRIES_IN_SUM(sbi) * 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) (NAT_JOURNAL_ENTRIES(sbi) - nats_in_cur= sum(jnl)) +#define MAX_SIT_JENTRIES(sbi, jnl) (SIT_JOURNAL_ENTRIES(sbi) - sits_in_cur= sum(jnl)) =20 static inline int update_nats_in_cursum(struct f2fs_journal *journal, int = i) { @@ -545,14 +566,6 @@ static inline int update_sits_in_cursum(struct f2fs_jo= urnal *journal, int i) return before; } =20 -static inline bool __has_cursum_space(struct f2fs_journal *journal, - int size, int type) -{ - if (type =3D=3D NAT_JOURNAL) - return size <=3D MAX_NAT_JENTRIES(journal); - return size <=3D MAX_SIT_JENTRIES(journal); -} - /* for inline stuff */ #define DEF_INLINE_RESERVED_SIZE 1 static inline int get_extra_isize(struct inode *inode); @@ -1750,6 +1763,7 @@ struct f2fs_sb_info { unsigned int log_sectors_per_block; /* log2 sectors per block */ unsigned int log_blocksize; /* log2 block size */ unsigned int blocksize; /* block size */ + unsigned int sum_blocksize; /* summary block size */ unsigned int root_ino_num; /* root inode number*/ unsigned int node_ino_num; /* node inode number*/ unsigned int meta_ino_num; /* meta inode number*/ @@ -2813,6 +2827,14 @@ static inline block_t __start_sum_addr(struct f2fs_s= b_info *sbi) return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); } =20 +static inline bool __has_cursum_space(struct f2fs_sb_info *sbi, + struct f2fs_journal *journal, int size, int type) +{ + if (type =3D=3D NAT_JOURNAL) + return size <=3D MAX_NAT_JENTRIES(sbi, journal); + return size <=3D MAX_SIT_JENTRIES(sbi, journal); +} + extern void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync); static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, struct inode *inode, bool is_inode) @@ -3956,7 +3978,8 @@ void f2fs_wait_on_block_writeback_range(struct inode = *inode, block_t blkaddr, block_t len); 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= ); -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); void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *c= pc); int f2fs_check_and_fix_write_pointer(struct f2fs_sb_info *sbi); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 384fa7e2085b..65c819d08807 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1769,8 +1769,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sb= i, =20 sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); =20 - segno =3D rounddown(segno, SUMS_PER_BLOCK); - sum_blk_cnt =3D DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK); + segno =3D rounddown(segno, SUMS_PER_BLOCK(sbi)); + sum_blk_cnt =3D DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK(sbi)); /* readahead multi ssa blocks those have contiguous address */ if (__is_large_section(sbi)) f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), @@ -1780,17 +1780,17 @@ static int do_garbage_collect(struct f2fs_sb_info *= sbi, while (segno < end_segno) { struct folio *sum_folio =3D f2fs_get_sum_folio(sbi, segno); =20 - segno +=3D SUMS_PER_BLOCK; + segno +=3D SUMS_PER_BLOCK(sbi); if (IS_ERR(sum_folio)) { int err =3D PTR_ERR(sum_folio); =20 - end_segno =3D segno - SUMS_PER_BLOCK; - segno =3D rounddown(start_segno, SUMS_PER_BLOCK); + end_segno =3D segno - SUMS_PER_BLOCK(sbi); + segno =3D rounddown(start_segno, SUMS_PER_BLOCK(sbi)); while (segno < end_segno) { sum_folio =3D filemap_get_folio(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); folio_put_refs(sum_folio, 2); - segno +=3D SUMS_PER_BLOCK; + segno +=3D SUMS_PER_BLOCK(sbi); } return err; } @@ -1806,8 +1806,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sb= i, /* find segment summary of victim */ struct folio *sum_folio =3D filemap_get_folio(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); - unsigned int block_end_segno =3D rounddown(segno, SUMS_PER_BLOCK) - + SUMS_PER_BLOCK; + unsigned int block_end_segno =3D rounddown(segno, SUMS_PER_BLOCK(sbi)) + + SUMS_PER_BLOCK(sbi); =20 if (block_end_segno > end_segno) block_end_segno =3D end_segno; @@ -1833,12 +1833,13 @@ static int do_garbage_collect(struct f2fs_sb_info *= sbi, migrated >=3D sbi->migration_granularity) continue; =20 - sum =3D SUM_BLK_PAGE_ADDR(sum_folio, cur_segno); - if (type !=3D GET_SUM_TYPE((&sum->footer))) { + sum =3D SUM_BLK_PAGE_ADDR(sbi, sum_folio, cur_segno); + if (type !=3D GET_SUM_TYPE(sum_footer(sbi, sum))) { f2fs_err(sbi, "Inconsistent segment (%u) type " "[%d, %d] in SSA and SIT", cur_segno, type, - GET_SUM_TYPE((&sum->footer))); + GET_SUM_TYPE( + sum_footer(sbi, sum))); f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_CORRUPTED_SUMMARY); continue; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 482a362f2625..f78d53ec59d4 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -606,7 +606,7 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t = nid, goto retry; } =20 - i =3D f2fs_lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0); + i =3D f2fs_lookup_journal_in_cursum(sbi, journal, NAT_JOURNAL, nid, 0); if (i >=3D 0) { ne =3D nat_in_journal(journal, i); node_info_from_raw_nat(ni, &ne); @@ -2937,7 +2937,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sb= i, /* scan the node segment */ last_offset =3D BLKS_PER_SEG(sbi); addr =3D START_BLOCK(sbi, segno); - sum_entry =3D &sum->entries[0]; + sum_entry =3D sum_entries(sum); =20 for (i =3D 0; i < last_offset; i +=3D nrpages, addr +=3D nrpages) { nrpages =3D bio_max_segs(last_offset - i); @@ -3078,7 +3078,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info = *sbi, * #2, flush nat entries to nat page. */ 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 =3D false; =20 if (to_journal) { @@ -3101,7 +3101,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info = *sbi, f2fs_bug_on(sbi, nat_get_blkaddr(ne) =3D=3D NEW_ADDR); =20 if (to_journal) { - offset =3D f2fs_lookup_journal_in_cursum(journal, + offset =3D f2fs_lookup_journal_in_cursum(sbi, journal, NAT_JOURNAL, nid, 1); f2fs_bug_on(sbi, offset < 0); raw_ne =3D &nat_in_journal(journal, offset); @@ -3172,7 +3172,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, = struct cp_control *cpc) * into nat entry set. */ if (enabled_nat_bits(sbi, cpc) || - !__has_cursum_space(journal, + !__has_cursum_space(sbi, journal, nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL)) remove_nats_in_journal(sbi); =20 @@ -3183,7 +3183,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, = struct cp_control *cpc) set_idx =3D setvec[found - 1]->set + 1; for (idx =3D 0; idx < found; idx++) __adjust_nat_entry_set(setvec[idx], &sets, - MAX_NAT_JENTRIES(journal)); + MAX_NAT_JENTRIES(sbi, journal)); } =20 /* flush dirty nats in nat entry set */ diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index c3415ebb9f50..a6bfc8e759cf 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -514,7 +514,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_inf= o *sbi, struct curseg_info *curseg =3D CURSEG_I(sbi, i); =20 if (curseg->segno =3D=3D segno) { - sum =3D curseg->sum_blk->entries[blkoff]; + sum =3D sum_entries(curseg->sum_blk)[blkoff]; goto got_it; } } @@ -522,8 +522,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_inf= o *sbi, sum_folio =3D f2fs_get_sum_folio(sbi, segno); if (IS_ERR(sum_folio)) return PTR_ERR(sum_folio); - sum_node =3D SUM_BLK_PAGE_ADDR(sum_folio, segno); - sum =3D sum_node->entries[blkoff]; + sum_node =3D SUM_BLK_PAGE_ADDR(sbi, sum_folio, segno); + sum =3D sum_entries(sum_node)[blkoff]; f2fs_folio_put(sum_folio, true); got_it: /* Use the locked dnode page and inode */ diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c26424f47686..1968a19f1e3c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2685,12 +2685,12 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_in= fo *sbi, bool for_ra) valid_sum_count +=3D f2fs_curseg_valid_blocks(sbi, i); } =20 - sum_in_page =3D (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - + sum_in_page =3D (sbi->sum_blocksize - 2 * SUM_JOURNAL_SIZE(sbi) - SUM_FOOTER_SIZE) / SUMMARY_SIZE; if (valid_sum_count <=3D sum_in_page) return 1; else if ((valid_sum_count - sum_in_page) <=3D - (PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) + (sbi->sum_blocksize - SUM_FOOTER_SIZE) / SUMMARY_SIZE) return 2; return 3; } @@ -2710,7 +2710,7 @@ void f2fs_update_meta_page(struct f2fs_sb_info *sbi, { struct folio *folio; =20 - if (SUMS_PER_BLOCK =3D=3D 1) + if (!f2fs_sb_has_packed_ssa(sbi)) folio =3D f2fs_grab_meta_folio(sbi, blk_addr); else folio =3D f2fs_get_meta_folio_retry(sbi, blk_addr); @@ -2728,7 +2728,7 @@ static void write_sum_page(struct f2fs_sb_info *sbi, { struct folio *folio; =20 - if (SUMS_PER_BLOCK =3D=3D 1) + if (!f2fs_sb_has_packed_ssa(sbi)) return f2fs_update_meta_page(sbi, (void *)sum_blk, GET_SUM_BLOCK(sbi, segno)); =20 @@ -2736,7 +2736,8 @@ static void write_sum_page(struct f2fs_sb_info *sbi, if (IS_ERR(folio)) return; =20 - 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); f2fs_folio_put(folio, true); } @@ -2755,11 +2756,11 @@ static void write_current_sum_page(struct f2fs_sb_i= nfo *sbi, mutex_lock(&curseg->curseg_mutex); =20 down_read(&curseg->journal_rwsem); - memcpy(&dst->journal, curseg->journal, SUM_JOURNAL_SIZE); + memcpy(sum_journal(sbi, dst), curseg->journal, SUM_JOURNAL_SIZE(sbi)); up_read(&curseg->journal_rwsem); =20 - memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); - memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); + memcpy(sum_entries(dst), sum_entries(src), SUM_ENTRY_SIZE(sbi)); + memcpy(sum_footer(sbi, dst), sum_footer(sbi, src), SUM_FOOTER_SIZE); =20 mutex_unlock(&curseg->curseg_mutex); =20 @@ -2932,7 +2933,7 @@ static void reset_curseg(struct f2fs_sb_info *sbi, in= t type, int modified) curseg->next_blkoff =3D 0; curseg->next_segno =3D NULL_SEGNO; =20 - sum_footer =3D &(curseg->sum_blk->footer); + sum_footer =3D sum_footer(sbi, curseg->sum_blk); memset(sum_footer, 0, sizeof(struct summary_footer)); =20 sanity_check_seg_type(sbi, seg_type); @@ -3078,11 +3079,11 @@ static int change_curseg(struct f2fs_sb_info *sbi, = int type) sum_folio =3D f2fs_get_sum_folio(sbi, new_segno); if (IS_ERR(sum_folio)) { /* 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, SUM_ENTRY_SIZE(sbi)); return PTR_ERR(sum_folio); } - sum_node =3D SUM_BLK_PAGE_ADDR(sum_folio, new_segno); - memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); + sum_node =3D SUM_BLK_PAGE_ADDR(sbi, sum_folio, new_segno); + memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE(sbi)); f2fs_folio_put(sum_folio, true); return 0; } @@ -3814,7 +3815,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi= , struct folio *folio, =20 f2fs_wait_discard_bio(sbi, *new_blkaddr); =20 - curseg->sum_blk->entries[curseg->next_blkoff] =3D *sum; + sum_entries(curseg->sum_blk)[curseg->next_blkoff] =3D *sum; if (curseg->alloc_type =3D=3D SSR) { curseg->next_blkoff =3D f2fs_find_next_ssr_block(sbi, curseg); } else { @@ -4183,7 +4184,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, = struct f2fs_summary *sum, } =20 curseg->next_blkoff =3D GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); - curseg->sum_blk->entries[curseg->next_blkoff] =3D *sum; + sum_entries(curseg->sum_blk)[curseg->next_blkoff] =3D *sum; =20 if (!recover_curseg || recover_newaddr) { if (!from_gc) @@ -4303,12 +4304,12 @@ static int read_compacted_summaries(struct f2fs_sb_= info *sbi) =20 /* Step 1: restore nat cache */ seg_i =3D CURSEG_I(sbi, CURSEG_HOT_DATA); - memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE); + memcpy(seg_i->journal, kaddr, SUM_JOURNAL_SIZE(sbi)); =20 /* Step 2: restore sit cache */ seg_i =3D CURSEG_I(sbi, CURSEG_COLD_DATA); - memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); - offset =3D 2 * SUM_JOURNAL_SIZE; + memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE(sbi), SUM_JOURNAL_SIZE(sb= i)); + offset =3D 2 * SUM_JOURNAL_SIZE(sbi); =20 /* Step 3: restore summary entries */ for (i =3D CURSEG_HOT_DATA; i <=3D CURSEG_COLD_DATA; i++) { @@ -4330,9 +4331,9 @@ static int read_compacted_summaries(struct f2fs_sb_in= fo *sbi) struct f2fs_summary *s; =20 s =3D (struct f2fs_summary *)(kaddr + offset); - seg_i->sum_blk->entries[j] =3D *s; + sum_entries(seg_i->sum_blk)[j] =3D *s; offset +=3D SUMMARY_SIZE; - if (offset + SUMMARY_SIZE <=3D PAGE_SIZE - + if (offset + SUMMARY_SIZE <=3D sbi->sum_blocksize - SUM_FOOTER_SIZE) continue; =20 @@ -4388,7 +4389,7 @@ static int read_normal_summaries(struct f2fs_sb_info = *sbi, int type) =20 if (IS_NODESEG(type)) { if (__exist_node_summaries(sbi)) { - struct f2fs_summary *ns =3D &sum->entries[0]; + struct f2fs_summary *ns =3D sum_entries(sum); int i; =20 for (i =3D 0; i < BLKS_PER_SEG(sbi); i++, ns++) { @@ -4408,11 +4409,13 @@ static int read_normal_summaries(struct f2fs_sb_inf= o *sbi, int type) =20 /* update journal info */ down_write(&curseg->journal_rwsem); - memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE); + memcpy(curseg->journal, sum_journal(sbi, sum), SUM_JOURNAL_SIZE(sbi)); up_write(&curseg->journal_rwsem); =20 - memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE); - memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE); + memcpy(sum_entries(curseg->sum_blk), sum_entries(sum), + SUM_ENTRY_SIZE(sbi)); + memcpy(sum_footer(sbi, curseg->sum_blk), sum_footer(sbi, sum), + SUM_FOOTER_SIZE); curseg->next_segno =3D segno; reset_curseg(sbi, type, 0); curseg->alloc_type =3D ckpt->alloc_type[type]; @@ -4456,8 +4459,8 @@ static int restore_curseg_summaries(struct f2fs_sb_in= fo *sbi) } =20 /* sanity check for summary blocks */ - if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || - sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) { + if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES(sbi) || + sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES(sbi)) { f2fs_err(sbi, "invalid journal entries nats %u sits %u", nats_in_cursum(nat_j), sits_in_cursum(sit_j)); return -EINVAL; @@ -4481,13 +4484,13 @@ static void write_compacted_summaries(struct f2fs_s= b_info *sbi, block_t blkaddr) =20 /* Step 1: write nat cache */ seg_i =3D CURSEG_I(sbi, CURSEG_HOT_DATA); - memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); - written_size +=3D SUM_JOURNAL_SIZE; + memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE(sbi)); + written_size +=3D SUM_JOURNAL_SIZE(sbi); =20 /* Step 2: write sit cache */ seg_i =3D CURSEG_I(sbi, CURSEG_COLD_DATA); - memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); - written_size +=3D SUM_JOURNAL_SIZE; + memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE(sbi)); + written_size +=3D SUM_JOURNAL_SIZE(sbi); =20 /* Step 3: write summary entries */ for (i =3D CURSEG_HOT_DATA; i <=3D CURSEG_COLD_DATA; i++) { @@ -4500,7 +4503,7 @@ static void write_compacted_summaries(struct f2fs_sb_= info *sbi, block_t blkaddr) written_size =3D 0; } summary =3D (struct f2fs_summary *)(kaddr + written_size); - *summary =3D seg_i->sum_blk->entries[j]; + *summary =3D sum_entries(seg_i->sum_blk)[j]; written_size +=3D SUMMARY_SIZE; =20 if (written_size + SUMMARY_SIZE <=3D PAGE_SIZE - @@ -4545,8 +4548,9 @@ void f2fs_write_node_summaries(struct f2fs_sb_info *s= bi, block_t start_blk) write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); } =20 -int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, - unsigned int val, int alloc) +int f2fs_lookup_journal_in_cursum(struct f2fs_sb_info *sbi, + struct f2fs_journal *journal, int type, + unsigned int val, int alloc) { int i; =20 @@ -4555,13 +4559,13 @@ int f2fs_lookup_journal_in_cursum(struct f2fs_journ= al *journal, int type, if (le32_to_cpu(nid_in_journal(journal, i)) =3D=3D val) 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); } else if (type =3D=3D SIT_JOURNAL) { for (i =3D 0; i < sits_in_cursum(journal); i++) if (le32_to_cpu(segno_in_journal(journal, i)) =3D=3D val) 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 -1; @@ -4709,8 +4713,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 * them in sit entry set. */ - if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) || - !to_journal) + if (!__has_cursum_space(sbi, journal, + sit_i->dirty_sentries, SIT_JOURNAL) || !to_journal) remove_sits_in_journal(sbi); =20 /* @@ -4727,7 +4731,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi,= struct cp_control *cpc) unsigned int segno =3D start_segno; =20 if (to_journal && - !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL)) + !__has_cursum_space(sbi, journal, ses->entry_cnt, + SIT_JOURNAL)) to_journal =3D false; =20 if (to_journal) { @@ -4755,7 +4760,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi,= struct cp_control *cpc) } =20 if (to_journal) { - offset =3D f2fs_lookup_journal_in_cursum(journal, + offset =3D f2fs_lookup_journal_in_cursum(sbi, journal, SIT_JOURNAL, segno, 1); f2fs_bug_on(sbi, offset < 0); segno_in_journal(journal, offset) =3D @@ -4962,12 +4967,13 @@ static int build_curseg(struct f2fs_sb_info *sbi) =20 for (i =3D 0; i < NO_CHECK_TYPE; i++) { mutex_init(&array[i].curseg_mutex); - array[i].sum_blk =3D f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL); + array[i].sum_blk =3D f2fs_kzalloc(sbi, sbi->sum_blocksize, + GFP_KERNEL); if (!array[i].sum_blk) return -ENOMEM; init_rwsem(&array[i].journal_rwsem); array[i].journal =3D f2fs_kzalloc(sbi, - sizeof(struct f2fs_journal), GFP_KERNEL); + SUM_JOURNAL_SIZE(sbi), GFP_KERNEL); if (!array[i].journal) return -ENOMEM; array[i].seg_type =3D log_type_to_seg_type(i); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 07dcbcbeb7c6..0806f9e4ee9c 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -90,12 +90,12 @@ static inline void sanity_check_seg_type(struct f2fs_sb= _info *sbi, #define GET_ZONE_FROM_SEG(sbi, segno) \ GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno)) =20 -#define SUMS_PER_BLOCK (F2FS_BLKSIZE / F2FS_SUM_BLKSIZE) +#define SUMS_PER_BLOCK(sbi) ((sbi)->blocksize / (sbi)->sum_blocksize) #define GET_SUM_BLOCK(sbi, segno) \ - (SM_I(sbi)->ssa_blkaddr + (segno / SUMS_PER_BLOCK)) -#define GET_SUM_BLKOFF(segno) (segno % SUMS_PER_BLOCK) -#define SUM_BLK_PAGE_ADDR(folio, segno) \ - (folio_address(folio) + GET_SUM_BLKOFF(segno) * F2FS_SUM_BLKSIZE) + (SM_I(sbi)->ssa_blkaddr + (segno / SUMS_PER_BLOCK(sbi))) +#define GET_SUM_BLKOFF(sbi, segno) (segno % SUMS_PER_BLOCK(sbi)) +#define SUM_BLK_PAGE_ADDR(sbi, folio, segno) \ + (folio_address(folio) + GET_SUM_BLKOFF(sbi, segno) * (sbi)->sum_blocksize) =20 #define GET_SUM_TYPE(footer) ((footer)->entry_type) #define SET_SUM_TYPE(footer, type) ((footer)->entry_type =3D (type)) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c4c225e09dc4..cf97a72e96ca 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4080,20 +4080,6 @@ static int sanity_check_raw_super(struct f2fs_sb_inf= o *sbi, if (sanity_check_area_boundary(sbi, folio, index)) return -EFSCORRUPTED; =20 - /* - * 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; } =20 @@ -4277,6 +4263,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) le32_to_cpu(raw_super->log_sectors_per_block); sbi->log_blocksize =3D le32_to_cpu(raw_super->log_blocksize); sbi->blocksize =3D BIT(sbi->log_blocksize); + sbi->sum_blocksize =3D f2fs_sb_has_packed_ssa(sbi) ? + 4096 : sbi->blocksize; sbi->log_blocks_per_seg =3D le32_to_cpu(raw_super->log_blocks_per_seg); sbi->blocks_per_seg =3D BIT(sbi->log_blocks_per_seg); sbi->segs_per_sec =3D le32_to_cpu(raw_super->segs_per_sec); diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index a7880787cad3..394f7af3a102 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -17,7 +17,6 @@ #define F2FS_LOG_SECTORS_PER_BLOCK (PAGE_SHIFT - 9) /* log number for sect= or/blk */ #define F2FS_BLKSIZE PAGE_SIZE /* support only block =3D=3D page */ #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_EXTENSION_LEN 8 /* max size of extension */ =20 @@ -442,10 +441,8 @@ struct f2fs_sit_block { * from node's page's beginning to get a data block address. * ex) data_blkaddr =3D (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 SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ -#define SUM_ENTRY_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) =20 /* a summary entry for a block in a segment */ struct f2fs_summary { @@ -468,22 +465,6 @@ struct summary_footer { __le32 check_sum; /* summary checksum */ } __packed; =20 -#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 * summary blocks @@ -498,9 +479,16 @@ struct nat_journal_entry { struct f2fs_nat_entry ne; } __packed; =20 +/* + * The nat_journal structure is a placeholder whose actual size varies dep= ending + * on the use of packed_ssa. Therefore, it must always be accessed only th= rough + * specific sets of macros, and size calculations should use size-related = macros + * instead of sizeof(). + * Relevant macros: NAT_JOURNAL_ENTRIES, nat_in_journal, nid_in_journal, + * MAX_NAT_JENTRIES. + */ struct nat_journal { - struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; - __u8 reserved[NAT_JOURNAL_RESERVED]; + struct nat_journal_entry entries[0]; } __packed; =20 struct sit_journal_entry { @@ -508,14 +496,21 @@ struct sit_journal_entry { struct f2fs_sit_entry se; } __packed; =20 +/* + * The sit_journal structure is a placeholder whose actual size varies dep= ending + * on the use of packed_ssa. Therefore, it must always be accessed only th= rough + * specific sets of macros, and size calculations should use size-related = macros + * instead of sizeof(). + * Relevant macros: SIT_JOURNAL_ENTRIES, sit_in_journal, segno_in_journal, + * MAX_SIT_JENTRIES. + */ struct sit_journal { - struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; - __u8 reserved[SIT_JOURNAL_RESERVED]; + struct sit_journal_entry entries[0]; } __packed; =20 struct f2fs_extra_info { __le64 kbytes_written; - __u8 reserved[EXTRA_INFO_RESERVED]; + __u8 reserved[]; } __packed; =20 struct f2fs_journal { @@ -531,11 +526,33 @@ struct f2fs_journal { }; } __packed; =20 -/* Block-sized summary block structure */ +/* + * Block-sized summary block structure + * + * The f2fs_summary_block structure is a placeholder whose actual size var= ies + * depending on the use of packed_ssa. Therefore, it must always be access= ed + * only through specific sets of macros, and size calculations should use + * size-related macros instead of sizeof(). + * Relevant macros: F2FS_SUM_BLKSIZE, ENTRIES_IN_SUM, 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 entries[ENTRIES_IN_SUM]; - struct f2fs_journal journal; - struct summary_footer footer; + struct f2fs_summary entries[0]; + // struct f2fs_journal journal; + // struct summary_footer footer; } __packed; =20 /* --=20 2.52.0.457.g6b5491de43-goog