commit: 618f73248f1023e6d2f63dc6cfb37018d960a4c0 Author: Arisu Tachibana <alicef <AT> gentoo <DOT> org> AuthorDate: Fri Feb 20 02:25:02 2026 +0000 Commit: Arisu Tachibana <alicef <AT> gentoo <DOT> org> CommitDate: Fri Feb 20 02:25:02 2026 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=618f7324
Linux patch 6.19.3 Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org> 0000_README | 4 + 1002_linux-6.19.3.patch | 1667 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1671 insertions(+) diff --git a/0000_README b/0000_README index cf18adf6..9e447ca9 100644 --- a/0000_README +++ b/0000_README @@ -51,6 +51,10 @@ Patch: 1001_linux-6.19.2.patch From: https://www.kernel.org Desc: Linux 6.19.2 +Patch: 1002_linux-6.19.3.patch +From: https://www.kernel.org +Desc: Linux 6.19.3 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ Desc: Enable link security restrictions by default. diff --git a/1002_linux-6.19.3.patch b/1002_linux-6.19.3.patch new file mode 100644 index 00000000..d2343b7e --- /dev/null +++ b/1002_linux-6.19.3.patch @@ -0,0 +1,1667 @@ +diff --git a/Makefile b/Makefile +index f0eb659930b2c6..21df6350711986 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 19 +-SUBLEVEL = 2 ++SUBLEVEL = 3 + EXTRAVERSION = + NAME = Baby Opossum Posse + +diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi +index 4e20a8f2eb2580..95cc067995336c 100644 +--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi +@@ -1812,15 +1812,23 @@ + #size-cells = <0>; + + port@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <0>; +- ovl_2l1_in: endpoint { ++ ++ ovl_2l1_in: endpoint@1 { ++ reg = <1>; + remote-endpoint = <&mmsys_ep_ext>; + }; + }; + + port@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <1>; +- ovl_2l1_out: endpoint { ++ ++ ovl_2l1_out: endpoint@1 { ++ reg = <1>; + remote-endpoint = <&rdma1_in>; + }; + }; +@@ -1872,15 +1880,23 @@ + #size-cells = <0>; + + port@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <0>; +- rdma1_in: endpoint { ++ ++ rdma1_in: endpoint@1 { ++ reg = <1>; + remote-endpoint = <&ovl_2l1_out>; + }; + }; + + port@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <1>; +- rdma1_out: endpoint { ++ ++ rdma1_out: endpoint@1 { ++ reg = <1>; + remote-endpoint = <&dpi_in>; + }; + }; +@@ -2076,15 +2092,24 @@ + #size-cells = <0>; + + port@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <0>; +- dpi_in: endpoint { ++ ++ dpi_in: endpoint@1 { ++ reg = <1>; + remote-endpoint = <&rdma1_out>; + }; + }; + + port@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; + reg = <1>; +- dpi_out: endpoint { }; ++ ++ dpi_out: endpoint@1 { ++ reg = <1>; ++ }; + }; + }; + }; +diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c +index 170da98ad4f551..0fc02ca0645738 100644 +--- a/arch/loongarch/mm/kasan_init.c ++++ b/arch/loongarch/mm/kasan_init.c +@@ -40,39 +40,43 @@ static pgd_t kasan_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); + #define __pte_none(early, pte) (early ? pte_none(pte) : \ + ((pte_val(pte) & _PFN_MASK) == (unsigned long)__pa(kasan_early_shadow_page))) + +-void *kasan_mem_to_shadow(const void *addr) ++static void *mem_to_shadow(const void *addr) + { +- if (!kasan_enabled()) { ++ unsigned long offset = 0; ++ unsigned long maddr = (unsigned long)addr; ++ unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff; ++ ++ if (maddr >= FIXADDR_START) + return (void *)(kasan_early_shadow_page); +- } else { +- unsigned long maddr = (unsigned long)addr; +- unsigned long xrange = (maddr >> XRANGE_SHIFT) & 0xffff; +- unsigned long offset = 0; +- +- if (maddr >= FIXADDR_START) +- return (void *)(kasan_early_shadow_page); +- +- maddr &= XRANGE_SHADOW_MASK; +- switch (xrange) { +- case XKPRANGE_CC_SEG: +- offset = XKPRANGE_CC_SHADOW_OFFSET; +- break; +- case XKPRANGE_UC_SEG: +- offset = XKPRANGE_UC_SHADOW_OFFSET; +- break; +- case XKPRANGE_WC_SEG: +- offset = XKPRANGE_WC_SHADOW_OFFSET; +- break; +- case XKVRANGE_VC_SEG: +- offset = XKVRANGE_VC_SHADOW_OFFSET; +- break; +- default: +- WARN_ON(1); +- return NULL; +- } + +- return (void *)((maddr >> KASAN_SHADOW_SCALE_SHIFT) + offset); ++ maddr &= XRANGE_SHADOW_MASK; ++ switch (xrange) { ++ case XKPRANGE_CC_SEG: ++ offset = XKPRANGE_CC_SHADOW_OFFSET; ++ break; ++ case XKPRANGE_UC_SEG: ++ offset = XKPRANGE_UC_SHADOW_OFFSET; ++ break; ++ case XKPRANGE_WC_SEG: ++ offset = XKPRANGE_WC_SHADOW_OFFSET; ++ break; ++ case XKVRANGE_VC_SEG: ++ offset = XKVRANGE_VC_SHADOW_OFFSET; ++ break; ++ default: ++ WARN_ON(1); ++ return NULL; + } ++ ++ return (void *)((maddr >> KASAN_SHADOW_SCALE_SHIFT) + offset); ++} ++ ++void *kasan_mem_to_shadow(const void *addr) ++{ ++ if (kasan_enabled()) ++ return mem_to_shadow(addr); ++ else ++ return (void *)(kasan_early_shadow_page); + } + + const void *kasan_shadow_to_mem(const void *shadow_addr) +@@ -293,11 +297,8 @@ void __init kasan_init(void) + /* Maps everything to a single page of zeroes */ + kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE, true); + +- kasan_populate_early_shadow(kasan_mem_to_shadow((void *)VMALLOC_START), +- kasan_mem_to_shadow((void *)KFENCE_AREA_END)); +- +- /* Enable KASAN here before kasan_mem_to_shadow(). */ +- kasan_init_generic(); ++ kasan_populate_early_shadow(mem_to_shadow((void *)VMALLOC_START), ++ mem_to_shadow((void *)KFENCE_AREA_END)); + + /* Populate the linear mapping */ + for_each_mem_range(i, &pa_start, &pa_end) { +@@ -307,13 +308,13 @@ void __init kasan_init(void) + if (start >= end) + break; + +- kasan_map_populate((unsigned long)kasan_mem_to_shadow(start), +- (unsigned long)kasan_mem_to_shadow(end), NUMA_NO_NODE); ++ kasan_map_populate((unsigned long)mem_to_shadow(start), ++ (unsigned long)mem_to_shadow(end), NUMA_NO_NODE); + } + + /* Populate modules mapping */ +- kasan_map_populate((unsigned long)kasan_mem_to_shadow((void *)MODULES_VADDR), +- (unsigned long)kasan_mem_to_shadow((void *)MODULES_END), NUMA_NO_NODE); ++ kasan_map_populate((unsigned long)mem_to_shadow((void *)MODULES_VADDR), ++ (unsigned long)mem_to_shadow((void *)MODULES_END), NUMA_NO_NODE); + /* + * KAsan may reuse the contents of kasan_early_shadow_pte directly, so we + * should make sure that it maps the zero page read-only. +@@ -328,4 +329,5 @@ void __init kasan_init(void) + + /* At this point kasan is fully initialized. Enable error messages */ + init_task.kasan_depth = 0; ++ kasan_init_generic(); + } +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c +index db9b9a8e139c87..4565a58bb213f4 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu-impl.c +@@ -228,3 +228,17 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu) + + return smmu; + } ++ ++int __init arm_smmu_impl_module_init(void) ++{ ++ if (IS_ENABLED(CONFIG_ARM_SMMU_QCOM)) ++ return qcom_smmu_module_init(); ++ ++ return 0; ++} ++ ++void __exit arm_smmu_impl_module_exit(void) ++{ ++ if (IS_ENABLED(CONFIG_ARM_SMMU_QCOM)) ++ qcom_smmu_module_exit(); ++} +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +index 573085349df34f..22906d2c9a2db2 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c +@@ -774,10 +774,6 @@ struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) + { + const struct device_node *np = smmu->dev->of_node; + const struct of_device_id *match; +- static u8 tbu_registered; +- +- if (!tbu_registered++) +- platform_driver_register(&qcom_smmu_tbu_driver); + + #ifdef CONFIG_ACPI + if (np == NULL) { +@@ -802,3 +798,13 @@ struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) + + return smmu; + } ++ ++int __init qcom_smmu_module_init(void) ++{ ++ return platform_driver_register(&qcom_smmu_tbu_driver); ++} ++ ++void __exit qcom_smmu_module_exit(void) ++{ ++ platform_driver_unregister(&qcom_smmu_tbu_driver); ++} +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c +index 5e690cf85ec969..1e218fbea35a02 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c +@@ -2365,7 +2365,29 @@ static struct platform_driver arm_smmu_driver = { + .remove = arm_smmu_device_remove, + .shutdown = arm_smmu_device_shutdown, + }; +-module_platform_driver(arm_smmu_driver); ++ ++static int __init arm_smmu_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&arm_smmu_driver); ++ if (ret) ++ return ret; ++ ++ ret = arm_smmu_impl_module_init(); ++ if (ret) ++ platform_driver_unregister(&arm_smmu_driver); ++ ++ return ret; ++} ++module_init(arm_smmu_init); ++ ++static void __exit arm_smmu_exit(void) ++{ ++ arm_smmu_impl_module_exit(); ++ platform_driver_unregister(&arm_smmu_driver); ++} ++module_exit(arm_smmu_exit); + + MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); + MODULE_AUTHOR("Will Deacon <[email protected]>"); +diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h +index 2dbf3243b5ad2d..26d2e33cd328b8 100644 +--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h ++++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h +@@ -540,6 +540,11 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu); + struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu); + struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu); + ++int __init arm_smmu_impl_module_init(void); ++void __exit arm_smmu_impl_module_exit(void); ++int __init qcom_smmu_module_init(void); ++void __exit qcom_smmu_module_exit(void); ++ + void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx); + int arm_mmu500_reset(struct arm_smmu_device *smmu); + +diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c +index ccfc2d26dd3725..0798bfd0372e47 100644 +--- a/drivers/scsi/qla2xxx/qla_bsg.c ++++ b/drivers/scsi/qla2xxx/qla_bsg.c +@@ -1546,8 +1546,9 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) + ha->optrom_buffer = NULL; + ha->optrom_state = QLA_SWAITING; + mutex_unlock(&ha->optrom_mutex); +- bsg_job_done(bsg_job, bsg_reply->result, +- bsg_reply->reply_payload_rcv_len); ++ if (!rval) ++ bsg_job_done(bsg_job, bsg_reply->result, ++ bsg_reply->reply_payload_rcv_len); + return rval; + } + +@@ -2612,8 +2613,9 @@ qla2x00_manage_host_stats(struct bsg_job *bsg_job) + sizeof(struct ql_vnd_mng_host_stats_resp)); + + bsg_reply->result = DID_OK; +- bsg_job_done(bsg_job, bsg_reply->result, +- bsg_reply->reply_payload_rcv_len); ++ if (!ret) ++ bsg_job_done(bsg_job, bsg_reply->result, ++ bsg_reply->reply_payload_rcv_len); + + return ret; + } +@@ -2702,8 +2704,9 @@ qla2x00_get_host_stats(struct bsg_job *bsg_job) + bsg_job->reply_payload.sg_cnt, + data, response_len); + bsg_reply->result = DID_OK; +- bsg_job_done(bsg_job, bsg_reply->result, +- bsg_reply->reply_payload_rcv_len); ++ if (!ret) ++ bsg_job_done(bsg_job, bsg_reply->result, ++ bsg_reply->reply_payload_rcv_len); + + kfree(data); + host_stat_out: +@@ -2802,8 +2805,9 @@ reply: + bsg_job->reply_payload.sg_cnt, data, + response_len); + bsg_reply->result = DID_OK; +- bsg_job_done(bsg_job, bsg_reply->result, +- bsg_reply->reply_payload_rcv_len); ++ if (!ret) ++ bsg_job_done(bsg_job, bsg_reply->result, ++ bsg_reply->reply_payload_rcv_len); + + tgt_stat_out: + kfree(data); +@@ -2864,8 +2868,9 @@ qla2x00_manage_host_port(struct bsg_job *bsg_job) + bsg_job->reply_payload.sg_cnt, &rsp_data, + sizeof(struct ql_vnd_mng_host_port_resp)); + bsg_reply->result = DID_OK; +- bsg_job_done(bsg_job, bsg_reply->result, +- bsg_reply->reply_payload_rcv_len); ++ if (!ret) ++ bsg_job_done(bsg_job, bsg_reply->result, ++ bsg_reply->reply_payload_rcv_len); + + return ret; + } +@@ -3240,7 +3245,8 @@ int qla2x00_mailbox_passthru(struct bsg_job *bsg_job) + + bsg_job->reply_len = sizeof(*bsg_job->reply); + bsg_reply->result = DID_OK << 16; +- bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); ++ if (!ret) ++ bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + kfree(req_data); + +diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c +index 9f2cc5fb9f4562..d4505a4264460b 100644 +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -1401,12 +1401,16 @@ static const struct usb_device_id option_ids[] = { + .driver_info = NCTRL(0) | RSVD(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a0, 0xff), /* Telit FN20C04 (rmnet) */ + .driver_info = RSVD(0) | NCTRL(3) }, ++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a1, 0xff), /* Telit FN20C04 (RNDIS) */ ++ .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a2, 0xff), /* Telit FN920C04 (MBIM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a3, 0xff), /* Telit FN920C04 (ECM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a4, 0xff), /* Telit FN20C04 (rmnet) */ + .driver_info = RSVD(0) | NCTRL(3) }, ++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a6, 0xff), /* Telit FN920C04 (RNDIS) */ ++ .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a7, 0xff), /* Telit FN920C04 (MBIM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a8, 0xff), /* Telit FN920C04 (ECM) */ +@@ -1415,6 +1419,8 @@ static const struct usb_device_id option_ids[] = { + .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */ + .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, ++ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10ab, 0xff), /* Telit FN920C04 (RNDIS) */ ++ .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x30), /* Telit FE990B (rmnet) */ + .driver_info = NCTRL(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x40) }, +diff --git a/drivers/video/fbdev/riva/riva_hw.c b/drivers/video/fbdev/riva/riva_hw.c +index 8b829b7200642f..f292079566cfca 100644 +--- a/drivers/video/fbdev/riva/riva_hw.c ++++ b/drivers/video/fbdev/riva/riva_hw.c +@@ -436,6 +436,9 @@ static char nv3_arb(nv3_fifo_info * res_info, nv3_sim_state * state, nv3_arb_in + vmisses = 2; + eburst_size = state->memory_width * 1; + mburst_size = 32; ++ if (!state->mclk_khz) ++ return (0); ++ + gns = 1000000 * (gmisses*state->mem_page_miss + state->mem_latency)/state->mclk_khz; + ainfo->by_gfacc = gns*ainfo->gdrain_rate/1000000; + ainfo->wcmocc = 0; +diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c +index 5f0dd01fd83495..891ce7b76d637e 100644 +--- a/drivers/video/fbdev/smscufx.c ++++ b/drivers/video/fbdev/smscufx.c +@@ -932,7 +932,6 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) + { + struct ufx_data *dev = info->par; +- struct dloarea *area = NULL; + + if (!atomic_read(&dev->usb_active)) + return 0; +@@ -947,6 +946,10 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd, + + /* TODO: Help propose a standard fb.h ioctl to report mmap damage */ + if (cmd == UFX_IOCTL_REPORT_DAMAGE) { ++ struct dloarea *area __free(kfree) = kmalloc(sizeof(*area), GFP_KERNEL); ++ if (!area) ++ return -ENOMEM; ++ + /* If we have a damage-aware client, turn fb_defio "off" + * To avoid perf imact of unnecessary page fault handling. + * Done by resetting the delay for this fb_info to a very +@@ -956,7 +959,8 @@ static int ufx_ops_ioctl(struct fb_info *info, unsigned int cmd, + if (info->fbdefio) + info->fbdefio->delay = UFX_DEFIO_WRITE_DISABLE; + +- area = (struct dloarea *)arg; ++ if (copy_from_user(area, (u8 __user *)arg, sizeof(*area))) ++ return -EFAULT; + + if (area->x < 0) + area->x = 0; +diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c +index c30e69392a6236..86e00b9e0d1cfc 100644 +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -151,6 +151,12 @@ static void f2fs_finish_read_bio(struct bio *bio, bool in_task) + } + + dec_page_count(F2FS_F_SB(folio), __read_io_type(folio)); ++ ++ if (F2FS_F_SB(folio)->node_inode && is_node_folio(folio) && ++ f2fs_sanity_check_node_footer(F2FS_F_SB(folio), ++ folio, folio->index, NODE_TYPE_REGULAR, true)) ++ bio->bi_status = BLK_STS_IOERR; ++ + folio_end_read(folio, bio->bi_status == BLK_STS_OK); + } + +@@ -352,18 +358,27 @@ static void f2fs_write_end_io(struct bio *bio) + STOP_CP_REASON_WRITE_FAIL); + } + +- f2fs_bug_on(sbi, is_node_folio(folio) && +- folio->index != nid_of_node(folio)); ++ if (is_node_folio(folio)) { ++ f2fs_sanity_check_node_footer(sbi, folio, ++ folio->index, NODE_TYPE_REGULAR, true); ++ f2fs_bug_on(sbi, folio->index != nid_of_node(folio)); ++ } + + dec_page_count(sbi, type); ++ ++ /* ++ * we should access sbi before folio_end_writeback() to ++ * avoid racing w/ kill_f2fs_super() ++ */ ++ if (type == F2FS_WB_CP_DATA && !get_pages(sbi, type) && ++ wq_has_sleeper(&sbi->cp_wait)) ++ wake_up(&sbi->cp_wait); ++ + if (f2fs_in_warm_node_list(sbi, folio)) + f2fs_del_fsync_node_entry(sbi, folio); + folio_clear_f2fs_gcing(folio); + folio_end_writeback(folio); + } +- if (!get_pages(sbi, F2FS_WB_CP_DATA) && +- wq_has_sleeper(&sbi->cp_wait)) +- wake_up(&sbi->cp_wait); + + bio_put(bio); + } +@@ -1418,7 +1433,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) + + static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag) + { +- f2fs_down_read(&sbi->cp_enable_rwsem); + if (flag == F2FS_GET_BLOCK_PRE_AIO) + f2fs_down_read(&sbi->node_change); + else +@@ -1431,7 +1445,6 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag) + f2fs_up_read(&sbi->node_change); + else + f2fs_unlock_op(sbi); +- f2fs_up_read(&sbi->cp_enable_rwsem); + } + + int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) +@@ -1793,7 +1806,8 @@ out: + return err; + } + +-bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) ++static bool __f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len, ++ bool check_first) + { + struct f2fs_map_blocks map; + block_t last_lblk; +@@ -1815,10 +1829,17 @@ bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) + if (err || map.m_len == 0) + return false; + map.m_lblk += map.m_len; ++ if (check_first) ++ break; + } + return true; + } + ++bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) ++{ ++ return __f2fs_overwrite_io(inode, pos, len, false); ++} ++ + static int f2fs_xattr_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo) + { +@@ -3929,6 +3950,7 @@ static int check_swap_activate(struct swap_info_struct *sis, + + while (cur_lblock < last_lblock && cur_lblock < sis->max) { + struct f2fs_map_blocks map; ++ bool last_extent = false; + retry: + cond_resched(); + +@@ -3954,11 +3976,10 @@ retry: + pblock = map.m_pblk; + nr_pblocks = map.m_len; + +- if ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec || +- nr_pblocks % blks_per_sec || +- f2fs_is_sequential_zone_area(sbi, pblock)) { +- bool last_extent = false; +- ++ if (!last_extent && ++ ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec || ++ nr_pblocks % blks_per_sec || ++ f2fs_is_sequential_zone_area(sbi, pblock))) { + not_aligned++; + + nr_pblocks = roundup(nr_pblocks, blks_per_sec); +@@ -3979,8 +4000,8 @@ retry: + goto out; + } + +- if (!last_extent) +- goto retry; ++ /* lookup block mapping info after block migration */ ++ goto retry; + } + + if (cur_lblock + nr_pblocks >= sis->max) +@@ -4181,7 +4202,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, + * f2fs_map_lock and f2fs_balance_fs are not necessary. + */ + if ((flags & IOMAP_WRITE) && +- !f2fs_overwrite_io(inode, offset, length)) ++ !__f2fs_overwrite_io(inode, offset, length, true)) + map.m_may_create = true; + + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DIO); +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index 20edbb99b814a7..d9a8465cb2f4de 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -287,7 +287,7 @@ enum { + #define DEF_CP_INTERVAL 60 /* 60 secs */ + #define DEF_IDLE_INTERVAL 5 /* 5 secs */ + #define DEF_DISABLE_INTERVAL 5 /* 5 secs */ +-#define DEF_ENABLE_INTERVAL 5 /* 5 secs */ ++#define DEF_ENABLE_INTERVAL 16 /* 16 secs */ + #define DEF_DISABLE_QUICK_INTERVAL 1 /* 1 secs */ + #define DEF_UMOUNT_DISCARD_TIMEOUT 5 /* 5 secs */ + +@@ -521,13 +521,25 @@ 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)) + +-#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 sum_entries(sum) ((struct f2fs_summary *)(sum)) ++#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) + { +@@ -545,14 +557,6 @@ static inline int update_sits_in_cursum(struct f2fs_journal *journal, int i) + 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 */ + #define DEF_INLINE_RESERVED_SIZE 1 + static inline int get_extra_isize(struct inode *inode); +@@ -1525,6 +1529,15 @@ enum f2fs_lookup_mode { + LOOKUP_AUTO, + }; + ++/* For node type in __get_node_folio() */ ++enum node_type { ++ NODE_TYPE_REGULAR, ++ NODE_TYPE_INODE, ++ NODE_TYPE_XATTR, ++ NODE_TYPE_NON_INODE, ++}; ++ ++ + static inline int f2fs_test_bit(unsigned int nr, char *addr); + static inline void f2fs_set_bit(unsigned int nr, char *addr); + static inline void f2fs_clear_bit(unsigned int nr, char *addr); +@@ -1716,7 +1729,6 @@ struct f2fs_sb_info { + long interval_time[MAX_TIME]; /* to store thresholds */ + struct ckpt_req_control cprc_info; /* for checkpoint request control */ + struct cp_stats cp_stats; /* for time stat of checkpoint */ +- struct f2fs_rwsem cp_enable_rwsem; /* block cache/dio write */ + + struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */ + +@@ -1764,6 +1776,15 @@ struct f2fs_sb_info { + bool readdir_ra; /* readahead inode in readdir */ + u64 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 total_valid_block_count; /* # of valid blocks */ + block_t discard_blks; /* discard command candidats */ +@@ -2813,6 +2834,14 @@ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) + 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); + static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, + struct inode *inode, bool is_inode) +@@ -3857,6 +3886,9 @@ struct folio *f2fs_new_node_folio(struct dnode_of_data *dn, unsigned int ofs); + void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid); + struct folio *f2fs_get_node_folio(struct f2fs_sb_info *sbi, pgoff_t nid, + enum node_type node_type); ++int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi, ++ struct folio *folio, pgoff_t nid, ++ enum node_type ntype, bool in_irq); + struct folio *f2fs_get_inode_folio(struct f2fs_sb_info *sbi, pgoff_t ino); + struct folio *f2fs_get_xnode_folio(struct f2fs_sb_info *sbi, pgoff_t xnid); + int f2fs_move_node_folio(struct folio *node_folio, int gc_type); +@@ -3956,7 +3988,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 *cpc); + 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 384fa7e2085bf9..fa20bcd700588f 100644 +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1769,8 +1769,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + + sanity_check_seg_type(sbi, get_seg_entry(sbi, segno)->type); + +- segno = rounddown(segno, SUMS_PER_BLOCK); +- sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, SUMS_PER_BLOCK); ++ segno = rounddown(segno, sbi->sums_per_block); ++ sum_blk_cnt = DIV_ROUND_UP(end_segno - segno, sbi->sums_per_block); + /* 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 = f2fs_get_sum_folio(sbi, segno); + +- segno += SUMS_PER_BLOCK; ++ segno += sbi->sums_per_block; + if (IS_ERR(sum_folio)) { + int err = PTR_ERR(sum_folio); + +- end_segno = segno - SUMS_PER_BLOCK; +- segno = rounddown(start_segno, SUMS_PER_BLOCK); ++ end_segno = segno - sbi->sums_per_block; ++ segno = rounddown(start_segno, sbi->sums_per_block); + while (segno < end_segno) { + sum_folio = filemap_get_folio(META_MAPPING(sbi), + GET_SUM_BLOCK(sbi, segno)); + folio_put_refs(sum_folio, 2); +- segno += SUMS_PER_BLOCK; ++ segno += sbi->sums_per_block; + } + return err; + } +@@ -1806,8 +1806,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + /* find segment summary of victim */ + struct folio *sum_folio = filemap_get_folio(META_MAPPING(sbi), + GET_SUM_BLOCK(sbi, segno)); +- unsigned int block_end_segno = rounddown(segno, SUMS_PER_BLOCK) +- + SUMS_PER_BLOCK; ++ unsigned int block_end_segno = rounddown(segno, sbi->sums_per_block) ++ + sbi->sums_per_block; + + if (block_end_segno > end_segno) + block_end_segno = end_segno; +@@ -1833,12 +1833,13 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, + migrated >= sbi->migration_granularity) + continue; + +- sum = SUM_BLK_PAGE_ADDR(sum_folio, cur_segno); +- if (type != GET_SUM_TYPE((&sum->footer))) { ++ sum = SUM_BLK_PAGE_ADDR(sbi, sum_folio, cur_segno); ++ if (type != 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; +@@ -2096,6 +2097,7 @@ int f2fs_gc_range(struct f2fs_sb_info *sbi, + if (unlikely(f2fs_cp_error(sbi))) + return -EIO; + ++ stat_inc_gc_call_count(sbi, FOREGROUND); + for (segno = start_seg; segno <= end_seg; segno += SEGS_PER_SEC(sbi)) { + struct gc_inode_list gc_list = { + .ilist = LIST_HEAD_INIT(gc_list.ilist), +diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c +index 482a362f262543..591fcdf3ba77b9 100644 +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -606,7 +606,7 @@ 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) { + ne = nat_in_journal(journal, i); + node_info_from_raw_nat(ni, &ne); +@@ -1500,9 +1500,9 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) + f2fs_folio_put(afolio, err ? true : false); + } + +-static int sanity_check_node_footer(struct f2fs_sb_info *sbi, ++int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi, + struct folio *folio, pgoff_t nid, +- enum node_type ntype) ++ enum node_type ntype, bool in_irq) + { + if (unlikely(nid != nid_of_node(folio))) + goto out_err; +@@ -1527,12 +1527,13 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi, + goto out_err; + return 0; + out_err: +- f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, " +- "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", +- ntype, nid, nid_of_node(folio), ino_of_node(folio), +- ofs_of_node(folio), cpver_of_node(folio), +- next_blkaddr_of_node(folio)); + set_sbi_flag(sbi, SBI_NEED_FSCK); ++ f2fs_warn_ratelimited(sbi, "inconsistent node block, node_type:%d, nid:%lu, " ++ "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]", ++ ntype, nid, nid_of_node(folio), ino_of_node(folio), ++ ofs_of_node(folio), cpver_of_node(folio), ++ next_blkaddr_of_node(folio)); ++ + f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER); + return -EFSCORRUPTED; + } +@@ -1578,7 +1579,7 @@ repeat: + goto out_err; + } + page_hit: +- err = sanity_check_node_footer(sbi, folio, nid, ntype); ++ err = f2fs_sanity_check_node_footer(sbi, folio, nid, ntype, false); + if (!err) + return folio; + out_err: +@@ -1751,7 +1752,12 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted + + /* get old block addr of this node page */ + nid = nid_of_node(folio); +- f2fs_bug_on(sbi, folio->index != nid); ++ ++ if (f2fs_sanity_check_node_footer(sbi, folio, nid, ++ NODE_TYPE_REGULAR, false)) { ++ f2fs_handle_critical_error(sbi, STOP_CP_REASON_CORRUPTED_NID); ++ goto redirty_out; ++ } + + if (f2fs_get_node_info(sbi, nid, &ni, !do_balance)) + goto redirty_out; +@@ -1774,8 +1780,13 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted + goto redirty_out; + } + +- if (atomic && !test_opt(sbi, NOBARRIER)) +- fio.op_flags |= REQ_PREFLUSH | REQ_FUA; ++ if (atomic) { ++ if (!test_opt(sbi, NOBARRIER)) ++ fio.op_flags |= REQ_PREFLUSH | REQ_FUA; ++ if (IS_INODE(folio)) ++ set_dentry_mark(folio, ++ f2fs_need_dentry_mark(sbi, ino_of_node(folio))); ++ } + + /* should add to global list before clearing PAGECACHE status */ + if (f2fs_in_warm_node_list(sbi, folio)) { +@@ -1916,8 +1927,9 @@ continue_unlock: + if (is_inode_flag_set(inode, + FI_DIRTY_INODE)) + f2fs_update_inode(inode, folio); +- set_dentry_mark(folio, +- f2fs_need_dentry_mark(sbi, ino)); ++ if (!atomic) ++ set_dentry_mark(folio, ++ f2fs_need_dentry_mark(sbi, ino)); + } + /* may be written by other thread */ + if (!folio_test_dirty(folio)) +@@ -2937,7 +2949,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, + /* scan the node segment */ + last_offset = BLKS_PER_SEG(sbi); + 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) { + nrpages = bio_max_segs(last_offset - i); +@@ -3078,7 +3090,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 = false; + + if (to_journal) { +@@ -3101,7 +3113,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi, + f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR); + + if (to_journal) { +- offset = f2fs_lookup_journal_in_cursum(journal, ++ offset = f2fs_lookup_journal_in_cursum(sbi, journal, + NAT_JOURNAL, nid, 1); + f2fs_bug_on(sbi, offset < 0); + raw_ne = &nat_in_journal(journal, offset); +@@ -3172,7 +3184,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); + +@@ -3183,7 +3195,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) + set_idx = setvec[found - 1]->set + 1; + for (idx = 0; idx < found; idx++) + __adjust_nat_entry_set(setvec[idx], &sets, +- MAX_NAT_JENTRIES(journal)); ++ MAX_NAT_JENTRIES(sbi, journal)); + } + + /* flush dirty nats in nat entry set */ +diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h +index 9cb8dcf8d41760..824ac9f0e6e42a 100644 +--- a/fs/f2fs/node.h ++++ b/fs/f2fs/node.h +@@ -52,14 +52,6 @@ enum { + IS_PREALLOC, /* nat entry is preallocated */ + }; + +-/* For node type in __get_node_folio() */ +-enum node_type { +- NODE_TYPE_REGULAR, +- NODE_TYPE_INODE, +- NODE_TYPE_XATTR, +- NODE_TYPE_NON_INODE, +-}; +- + /* + * For node information + */ +diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c +index c3415ebb9f5053..a6bfc8e759cf40 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_info *sbi, + struct curseg_info *curseg = CURSEG_I(sbi, i); + + if (curseg->segno == segno) { +- sum = curseg->sum_blk->entries[blkoff]; ++ sum = sum_entries(curseg->sum_blk)[blkoff]; + 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); + if (IS_ERR(sum_folio)) + return PTR_ERR(sum_folio); +- sum_node = SUM_BLK_PAGE_ADDR(sum_folio, segno); +- sum = sum_node->entries[blkoff]; ++ sum_node = SUM_BLK_PAGE_ADDR(sbi, sum_folio, segno); ++ sum = 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 c26424f4768635..90d0bac9d29400 100644 +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -2685,12 +2685,12 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) + valid_sum_count += f2fs_curseg_valid_blocks(sbi, i); + } + +- sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - ++ sum_in_page = (sbi->blocksize - 2 * sbi->sum_journal_size - + SUM_FOOTER_SIZE) / SUMMARY_SIZE; + if (valid_sum_count <= sum_in_page) + return 1; + else if ((valid_sum_count - sum_in_page) <= +- (PAGE_SIZE - SUM_FOOTER_SIZE) / SUMMARY_SIZE) ++ (sbi->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; + +- if (SUMS_PER_BLOCK == 1) ++ if (!f2fs_sb_has_packed_ssa(sbi)) + folio = f2fs_grab_meta_folio(sbi, blk_addr); + else + folio = 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; + +- if (SUMS_PER_BLOCK == 1) ++ if (!f2fs_sb_has_packed_ssa(sbi)) + return f2fs_update_meta_page(sbi, (void *)sum_blk, + GET_SUM_BLOCK(sbi, segno)); + +@@ -2736,7 +2736,8 @@ static void write_sum_page(struct f2fs_sb_info *sbi, + if (IS_ERR(folio)) + 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); + f2fs_folio_put(folio, true); + } +@@ -2755,11 +2756,11 @@ static void write_current_sum_page(struct f2fs_sb_info *sbi, + mutex_lock(&curseg->curseg_mutex); + + 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); + +- memcpy(dst->entries, src->entries, SUM_ENTRY_SIZE); +- memcpy(&dst->footer, &src->footer, SUM_FOOTER_SIZE); ++ memcpy(sum_entries(dst), sum_entries(src), sbi->sum_entry_size); ++ memcpy(sum_footer(sbi, dst), sum_footer(sbi, src), SUM_FOOTER_SIZE); + + mutex_unlock(&curseg->curseg_mutex); + +@@ -2932,7 +2933,7 @@ static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) + curseg->next_blkoff = 0; + 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)); + + sanity_check_seg_type(sbi, seg_type); +@@ -3078,11 +3079,11 @@ static int change_curseg(struct f2fs_sb_info *sbi, int type) + sum_folio = 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, sbi->sum_entry_size); + return PTR_ERR(sum_folio); + } +- sum_node = SUM_BLK_PAGE_ADDR(sum_folio, new_segno); +- memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); ++ sum_node = SUM_BLK_PAGE_ADDR(sbi, sum_folio, new_segno); ++ memcpy(curseg->sum_blk, sum_node, sbi->sum_entry_size); + 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, + + 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) { + curseg->next_blkoff = 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, + } + + 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 (!from_gc) +@@ -4303,12 +4304,12 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) + + /* Step 1: restore nat cache */ + 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 */ + seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); +- memcpy(seg_i->journal, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); +- offset = 2 * SUM_JOURNAL_SIZE; ++ memcpy(seg_i->journal, kaddr + sbi->sum_journal_size, sbi->sum_journal_size); ++ offset = 2 * sbi->sum_journal_size; + + /* Step 3: restore summary entries */ + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { +@@ -4330,9 +4331,9 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) + struct f2fs_summary *s; + + s = (struct f2fs_summary *)(kaddr + offset); +- seg_i->sum_blk->entries[j] = *s; ++ sum_entries(seg_i->sum_blk)[j] = *s; + offset += SUMMARY_SIZE; +- if (offset + SUMMARY_SIZE <= PAGE_SIZE - ++ if (offset + SUMMARY_SIZE <= sbi->blocksize - + SUM_FOOTER_SIZE) + continue; + +@@ -4388,7 +4389,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) + + if (IS_NODESEG(type)) { + if (__exist_node_summaries(sbi)) { +- struct f2fs_summary *ns = &sum->entries[0]; ++ struct f2fs_summary *ns = sum_entries(sum); + int i; + + for (i = 0; i < BLKS_PER_SEG(sbi); i++, ns++) { +@@ -4408,11 +4409,13 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) + + /* update journal info */ + 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); + +- 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), ++ sbi->sum_entry_size); ++ memcpy(sum_footer(sbi, curseg->sum_blk), sum_footer(sbi, sum), ++ SUM_FOOTER_SIZE); + curseg->next_segno = segno; + reset_curseg(sbi, type, 0); + curseg->alloc_type = ckpt->alloc_type[type]; +@@ -4456,8 +4459,8 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) + } + + /* 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) > sbi->nat_journal_entries || ++ sits_in_cursum(sit_j) > sbi->sit_journal_entries) { + 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_sb_info *sbi, block_t blkaddr) + + /* Step 1: write nat cache */ + seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA); +- memcpy(kaddr, seg_i->journal, SUM_JOURNAL_SIZE); +- written_size += SUM_JOURNAL_SIZE; ++ memcpy(kaddr, seg_i->journal, sbi->sum_journal_size); ++ written_size += sbi->sum_journal_size; + + /* Step 2: write sit cache */ + seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA); +- memcpy(kaddr + written_size, seg_i->journal, SUM_JOURNAL_SIZE); +- written_size += SUM_JOURNAL_SIZE; ++ memcpy(kaddr + written_size, seg_i->journal, sbi->sum_journal_size); ++ written_size += sbi->sum_journal_size; + + /* Step 3: write summary entries */ + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { +@@ -4500,10 +4503,10 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) + written_size = 0; + } + 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; + +- if (written_size + SUMMARY_SIZE <= PAGE_SIZE - ++ if (written_size + SUMMARY_SIZE <= sbi->blocksize - + SUM_FOOTER_SIZE) + continue; + +@@ -4545,8 +4548,9 @@ void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) + write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); + } + +-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; + +@@ -4555,13 +4559,13 @@ int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type, + if (le32_to_cpu(nid_in_journal(journal, i)) == 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 == SIT_JOURNAL) { + for (i = 0; i < sits_in_cursum(journal); i++) + if (le32_to_cpu(segno_in_journal(journal, i)) == 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); + + /* +@@ -4727,7 +4731,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) + unsigned int segno = start_segno; + + 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; + + if (to_journal) { +@@ -4755,7 +4760,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) + } + + if (to_journal) { +- offset = f2fs_lookup_journal_in_cursum(journal, ++ offset = f2fs_lookup_journal_in_cursum(sbi, journal, + SIT_JOURNAL, segno, 1); + f2fs_bug_on(sbi, offset < 0); + segno_in_journal(journal, offset) = +@@ -4962,12 +4967,13 @@ static int build_curseg(struct f2fs_sb_info *sbi) + + for (i = 0; i < NO_CHECK_TYPE; i++) { + 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) + return -ENOMEM; + init_rwsem(&array[i].journal_rwsem); + array[i].journal = f2fs_kzalloc(sbi, +- sizeof(struct f2fs_journal), GFP_KERNEL); ++ sbi->sum_journal_size, GFP_KERNEL); + if (!array[i].journal) + return -ENOMEM; + array[i].seg_type = log_type_to_seg_type(i); +diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h +index 07dcbcbeb7c6d3..3094f2de37b636 100644 +--- a/fs/f2fs/segment.h ++++ b/fs/f2fs/segment.h +@@ -90,12 +90,11 @@ 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)) + +-#define SUMS_PER_BLOCK (F2FS_BLKSIZE / F2FS_SUM_BLKSIZE) + #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 / (sbi)->sums_per_block)) ++#define GET_SUM_BLKOFF(sbi, segno) (segno % (sbi)->sums_per_block) ++#define SUM_BLK_PAGE_ADDR(sbi, folio, segno) \ ++ (folio_address(folio) + GET_SUM_BLKOFF(sbi, segno) * (sbi)->sum_blocksize) + + #define GET_SUM_TYPE(footer) ((footer)->entry_type) + #define SET_SUM_TYPE(footer, type) ((footer)->entry_type = (type)) +diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c +index c4c225e09dc470..6be6d7372badf5 100644 +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -2636,11 +2636,10 @@ restore_flag: + static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + { + unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16; +- long long start, writeback, lock, sync_inode, end; ++ long long start, writeback, end; + int ret; + +- f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld", +- __func__, ++ f2fs_info(sbi, "f2fs_enable_checkpoint() starts, meta: %lld, node: %lld, data: %lld", + get_pages(sbi, F2FS_DIRTY_META), + get_pages(sbi, F2FS_DIRTY_NODES), + get_pages(sbi, F2FS_DIRTY_DATA)); +@@ -2659,18 +2658,11 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + } + writeback = ktime_get(); + +- f2fs_down_write(&sbi->cp_enable_rwsem); +- +- lock = ktime_get(); +- +- if (get_pages(sbi, F2FS_DIRTY_DATA)) +- sync_inodes_sb(sbi->sb); ++ sync_inodes_sb(sbi->sb); + + if (unlikely(get_pages(sbi, F2FS_DIRTY_DATA))) +- f2fs_warn(sbi, "%s: has some unwritten data: %lld", +- __func__, get_pages(sbi, F2FS_DIRTY_DATA)); +- +- sync_inode = ktime_get(); ++ f2fs_warn(sbi, "checkpoint=enable has some unwritten data: %lld", ++ get_pages(sbi, F2FS_DIRTY_DATA)); + + f2fs_down_write(&sbi->gc_lock); + f2fs_dirty_to_prefree(sbi); +@@ -2679,13 +2671,6 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + set_sbi_flag(sbi, SBI_IS_DIRTY); + f2fs_up_write(&sbi->gc_lock); + +- f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld", +- __func__, +- get_pages(sbi, F2FS_DIRTY_META), +- get_pages(sbi, F2FS_DIRTY_IMETA), +- get_pages(sbi, F2FS_DIRTY_NODES), +- get_pages(sbi, F2FS_DIRTY_DENTS), +- get_pages(sbi, F2FS_DIRTY_QDATA)); + ret = f2fs_sync_fs(sbi->sb, 1); + if (ret) + f2fs_err(sbi, "%s sync_fs failed, ret: %d", __func__, ret); +@@ -2693,17 +2678,11 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) + /* Let's ensure there's no pending checkpoint anymore */ + f2fs_flush_ckpt_thread(sbi); + +- f2fs_up_write(&sbi->cp_enable_rwsem); +- + end = ktime_get(); + +- f2fs_info(sbi, "%s end, writeback:%llu, " +- "lock:%llu, sync_inode:%llu, sync_fs:%llu", +- __func__, +- ktime_ms_delta(writeback, start), +- ktime_ms_delta(lock, writeback), +- ktime_ms_delta(sync_inode, lock), +- ktime_ms_delta(end, sync_inode)); ++ f2fs_info(sbi, "f2fs_enable_checkpoint() finishes, writeback:%llu, sync:%llu", ++ ktime_ms_delta(writeback, start), ++ ktime_ms_delta(end, writeback)); + return ret; + } + +@@ -4080,20 +4059,6 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi, + if (sanity_check_area_boundary(sbi, folio, index)) + 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; + } + +@@ -4304,6 +4269,18 @@ static void init_sb_info(struct f2fs_sb_info *sbi) + spin_lock_init(&sbi->gc_remaining_trials_lock); + atomic64_set(&sbi->current_atomic_write, 0); + ++ 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->interval_time[CP_TIME] = DEF_CP_INTERVAL; + sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; +@@ -4906,7 +4883,6 @@ try_onemore: + init_f2fs_rwsem(&sbi->node_change); + spin_lock_init(&sbi->stat_lock); + init_f2fs_rwsem(&sbi->cp_rwsem); +- init_f2fs_rwsem(&sbi->cp_enable_rwsem); + init_f2fs_rwsem(&sbi->quota_sem); + init_waitqueue_head(&sbi->cp_wait); + spin_lock_init(&sbi->error_lock); +diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c +index c42f4f979d13f3..353bf47959f36a 100644 +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -58,6 +58,7 @@ struct f2fs_attr { + const char *buf, size_t len); + int struct_type; + int offset; ++ int size; + int id; + }; + +@@ -344,11 +345,30 @@ static ssize_t main_blkaddr_show(struct f2fs_attr *a, + (unsigned long long)MAIN_BLKADDR(sbi)); + } + ++static ssize_t __sbi_show_value(struct f2fs_attr *a, ++ struct f2fs_sb_info *sbi, char *buf, ++ unsigned char *value) ++{ ++ switch (a->size) { ++ case 1: ++ return sysfs_emit(buf, "%u\n", *(u8 *)value); ++ case 2: ++ return sysfs_emit(buf, "%u\n", *(u16 *)value); ++ case 4: ++ return sysfs_emit(buf, "%u\n", *(u32 *)value); ++ case 8: ++ return sysfs_emit(buf, "%llu\n", *(u64 *)value); ++ default: ++ f2fs_bug_on(sbi, 1); ++ return sysfs_emit(buf, ++ "show sysfs node value with wrong type\n"); ++ } ++} ++ + static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + struct f2fs_sb_info *sbi, char *buf) + { + unsigned char *ptr = NULL; +- unsigned int *ui; + + ptr = __struct_ptr(sbi, a->struct_type); + if (!ptr) +@@ -428,9 +448,30 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, + atomic_read(&sbi->cp_call_count[BACKGROUND])); + #endif + +- ui = (unsigned int *)(ptr + a->offset); ++ return __sbi_show_value(a, sbi, buf, ptr + a->offset); ++} + +- return sysfs_emit(buf, "%u\n", *ui); ++static void __sbi_store_value(struct f2fs_attr *a, ++ struct f2fs_sb_info *sbi, ++ unsigned char *ui, unsigned long value) ++{ ++ switch (a->size) { ++ case 1: ++ *(u8 *)ui = value; ++ break; ++ case 2: ++ *(u16 *)ui = value; ++ break; ++ case 4: ++ *(u32 *)ui = value; ++ break; ++ case 8: ++ *(u64 *)ui = value; ++ break; ++ default: ++ f2fs_bug_on(sbi, 1); ++ f2fs_err(sbi, "store sysfs node value with wrong type"); ++ } + } + + static ssize_t __sbi_store(struct f2fs_attr *a, +@@ -749,7 +790,7 @@ out: + return count; + } + +- if (!strcmp(a->attr.name, "gc_pin_file_threshold")) { ++ if (!strcmp(a->attr.name, "gc_pin_file_thresh")) { + if (t > MAX_GC_FAILED_PINNED_FILES) + return -EINVAL; + sbi->gc_pin_file_threshold = t; +@@ -906,7 +947,7 @@ out: + return count; + } + +- *ui = (unsigned int)t; ++ __sbi_store_value(a, sbi, ptr + a->offset, t); + + return count; + } +@@ -1053,24 +1094,27 @@ static struct f2fs_attr f2fs_attr_sb_##_name = { \ + .id = F2FS_FEATURE_##_feat, \ + } + +-#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset) \ ++#define F2FS_ATTR_OFFSET(_struct_type, _name, _mode, _show, _store, _offset, _size) \ + static struct f2fs_attr f2fs_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ + .struct_type = _struct_type, \ +- .offset = _offset \ ++ .offset = _offset, \ ++ .size = _size \ + } + + #define F2FS_RO_ATTR(struct_type, struct_name, name, elname) \ + F2FS_ATTR_OFFSET(struct_type, name, 0444, \ + f2fs_sbi_show, NULL, \ +- offsetof(struct struct_name, elname)) ++ offsetof(struct struct_name, elname), \ ++ sizeof_field(struct struct_name, elname)) + + #define F2FS_RW_ATTR(struct_type, struct_name, name, elname) \ + F2FS_ATTR_OFFSET(struct_type, name, 0644, \ + f2fs_sbi_show, f2fs_sbi_store, \ +- offsetof(struct struct_name, elname)) ++ offsetof(struct struct_name, elname), \ ++ sizeof_field(struct struct_name, elname)) + + #define F2FS_GENERAL_RO_ATTR(name) \ + static struct f2fs_attr f2fs_attr_##name = __ATTR(name, 0444, name##_show, NULL) +diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h +index a7880787cad366..dc41722fcc9dde 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 sector/blk */ + #define F2FS_BLKSIZE PAGE_SIZE /* support only block == 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 */ + +@@ -442,10 +441,8 @@ struct f2fs_sit_block { + * from node's page's beginning to get a data block address. + * 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 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 */ + struct f2fs_summary { +@@ -468,22 +465,6 @@ struct summary_footer { + __le32 check_sum; /* summary checksum */ + } __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 + * summary blocks +@@ -498,9 +479,16 @@ struct nat_journal_entry { + struct f2fs_nat_entry ne; + } __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_entry entries[NAT_JOURNAL_ENTRIES]; +- __u8 reserved[NAT_JOURNAL_RESERVED]; ++ struct nat_journal_entry entries[0]; + } __packed; + + struct sit_journal_entry { +@@ -508,14 +496,21 @@ struct sit_journal_entry { + struct f2fs_sit_entry se; + } __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_entry entries[SIT_JOURNAL_ENTRIES]; +- __u8 reserved[SIT_JOURNAL_RESERVED]; ++ struct sit_journal_entry entries[0]; + } __packed; + + struct f2fs_extra_info { + __le64 kbytes_written; +- __u8 reserved[EXTRA_INFO_RESERVED]; ++ __u8 reserved[]; + } __packed; + + struct f2fs_journal { +@@ -531,11 +526,33 @@ struct f2fs_journal { + }; + } __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 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; + + /*
