From 8bb787513eda6d94776ff8601fb3bc5ce1da42cd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Feb 2026 13:57:31 +0100 Subject: [PATCH] 6.18-stable patches added patches: f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch fbdev-rivafb-fix-divide-error-in-nv3_arb.patch fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch --- ...-atomic-commit-and-checkpoint-writes.patch | 98 +++ ...access-in-sysfs-attribute-read-write.patch | 170 +++++ ...o-add-gc-count-stat-in-f2fs_gc_range.patch | 31 + ...ng-wrong-physical-block-for-swapfile.patch | 140 ++++ ...ix-to-avoid-uaf-in-f2fs_write_end_io.patch | 75 ++ ...ename-w-gc_pin_file_thresh-correctly.patch | 32 + ...fs_overwrite_io-for-f2fs_iomap_begin.patch | 75 ++ ...lock-size-without-packed_ssa-feature.patch | 721 ++++++++++++++++++ ...v-rivafb-fix-divide-error-in-nv3_arb.patch | 65 ++ ...rly-copy-ioctl-memory-to-kernelspace.patch | 57 ++ queue-6.18/series | 10 + 11 files changed, 1474 insertions(+) create mode 100644 queue-6.18/f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch create mode 100644 queue-6.18/f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch create mode 100644 queue-6.18/f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch create mode 100644 queue-6.18/f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch create mode 100644 queue-6.18/f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch create mode 100644 queue-6.18/f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch create mode 100644 queue-6.18/f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch create mode 100644 queue-6.18/f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch create mode 100644 queue-6.18/fbdev-rivafb-fix-divide-error-in-nv3_arb.patch create mode 100644 queue-6.18/fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch diff --git a/queue-6.18/f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch b/queue-6.18/f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch new file mode 100644 index 0000000000..0615612874 --- /dev/null +++ b/queue-6.18/f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch @@ -0,0 +1,98 @@ +From 7633a7387eb4d0259d6bea945e1d3469cd135bbc Mon Sep 17 00:00:00 2001 +From: Yongpeng Yang +Date: Tue, 6 Jan 2026 20:12:11 +0800 +Subject: f2fs: fix IS_CHECKPOINTED flag inconsistency issue caused by concurrent atomic commit and checkpoint writes + +From: Yongpeng Yang + +commit 7633a7387eb4d0259d6bea945e1d3469cd135bbc upstream. + +During SPO tests, when mounting F2FS, an -EINVAL error was returned from +f2fs_recover_inode_page. The issue occurred under the following scenario + +Thread A Thread B +f2fs_ioc_commit_atomic_write + - f2fs_do_sync_file // atomic = true + - f2fs_fsync_node_pages + : last_folio = inode folio + : schedule before folio_lock(last_folio) f2fs_write_checkpoint + - block_operations// writeback last_folio + - schedule before f2fs_flush_nat_entries + : set_fsync_mark(last_folio, 1) + : set_dentry_mark(last_folio, 1) + : folio_mark_dirty(last_folio) + - __write_node_folio(last_folio) + : f2fs_down_read(&sbi->node_write)//block + - f2fs_flush_nat_entries + : {struct nat_entry}->flag |= BIT(IS_CHECKPOINTED) + - unblock_operations + : f2fs_up_write(&sbi->node_write) + f2fs_write_checkpoint//return + : f2fs_do_write_node_page() +f2fs_ioc_commit_atomic_write//return + SPO + +Thread A calls f2fs_need_dentry_mark(sbi, ino), and the last_folio has +already been written once. However, the {struct nat_entry}->flag did not +have the IS_CHECKPOINTED set, causing set_dentry_mark(last_folio, 1) and +write last_folio again after Thread B finishes f2fs_write_checkpoint. + +After SPO and reboot, it was detected that {struct node_info}->blk_addr +was not NULL_ADDR because Thread B successfully write the checkpoint. + +This issue only occurs in atomic write scenarios. For regular file +fsync operations, the folio must be dirty. If +block_operations->f2fs_sync_node_pages successfully submit the folio +write, this path will not be executed. Otherwise, the +f2fs_write_checkpoint will need to wait for the folio write submission +to complete, as sbi->nr_pages[F2FS_DIRTY_NODES] > 0. Therefore, the +situation where f2fs_need_dentry_mark checks that the {struct +nat_entry}->flag /wo the IS_CHECKPOINTED flag, but the folio write has +already been submitted, will not occur. + +Therefore, for atomic file fsync, sbi->node_write should be acquired +through __write_node_folio to ensure that the IS_CHECKPOINTED flag +correctly indicates that the checkpoint write has been completed. + +Fixes: 608514deba38 ("f2fs: set fsync mark only for the last dnode") +Cc: stable@kernel.org +Signed-off-by: Sheng Yong +Signed-off-by: Jinbao Liu +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/node.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -1774,8 +1774,13 @@ static bool __write_node_folio(struct fo + 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 +1921,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)) diff --git a/queue-6.18/f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch b/queue-6.18/f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch new file mode 100644 index 0000000000..e499fc2eed --- /dev/null +++ b/queue-6.18/f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch @@ -0,0 +1,170 @@ +From 98ea0039dbfdd00e5cc1b9a8afa40434476c0955 Mon Sep 17 00:00:00 2001 +From: Yongpeng Yang +Date: Wed, 7 Jan 2026 10:33:46 +0800 +Subject: f2fs: fix out-of-bounds access in sysfs attribute read/write + +From: Yongpeng Yang + +commit 98ea0039dbfdd00e5cc1b9a8afa40434476c0955 upstream. + +Some f2fs sysfs attributes suffer from out-of-bounds memory access and +incorrect handling of integer values whose size is not 4 bytes. + +For example: +vm:~# echo 65537 > /sys/fs/f2fs/vde/carve_out +vm:~# cat /sys/fs/f2fs/vde/carve_out +65537 +vm:~# echo 4294967297 > /sys/fs/f2fs/vde/atgc_age_threshold +vm:~# cat /sys/fs/f2fs/vde/atgc_age_threshold +1 + +carve_out maps to {struct f2fs_sb_info}->carve_out, which is a 8-bit +integer. However, the sysfs interface allows setting it to a value +larger than 255, resulting in an out-of-range update. + +atgc_age_threshold maps to {struct atgc_management}->age_threshold, +which is a 64-bit integer, but its sysfs interface cannot correctly set +values larger than UINT_MAX. + +The root causes are: +1. __sbi_store() treats all default values as unsigned int, which +prevents updating integers larger than 4 bytes and causes out-of-bounds +writes for integers smaller than 4 bytes. + +2. f2fs_sbi_show() also assumes all default values are unsigned int, +leading to out-of-bounds reads and incorrect access to integers larger +than 4 bytes. + +This patch introduces {struct f2fs_attr}->size to record the actual size +of the integer associated with each sysfs attribute. With this +information, sysfs read and write operations can correctly access and +update values according to their real data size, avoiding memory +corruption and truncation. + +Fixes: b59d0bae6ca3 ("f2fs: add sysfs support for controlling the gc_thread") +Cc: stable@kernel.org +Signed-off-by: Jinbao Liu +Signed-off-by: Yongpeng Yang +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/sysfs.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 52 insertions(+), 8 deletions(-) + +--- 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 + (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 + 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, +@@ -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_##_ + .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/queue-6.18/f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch b/queue-6.18/f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch new file mode 100644 index 0000000000..8907602d81 --- /dev/null +++ b/queue-6.18/f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch @@ -0,0 +1,31 @@ +From 761dac9073cd67d4705a94cd1af674945a117f4c Mon Sep 17 00:00:00 2001 +From: Zhiguo Niu +Date: Fri, 26 Dec 2025 10:56:04 +0800 +Subject: f2fs: fix to add gc count stat in f2fs_gc_range + +From: Zhiguo Niu + +commit 761dac9073cd67d4705a94cd1af674945a117f4c upstream. + +It missed the stat count in f2fs_gc_range. + +Cc: stable@kernel.org +Fixes: 9bf1dcbdfdc8 ("f2fs: fix to account gc stats correctly") +Signed-off-by: Zhiguo Niu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/gc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -2093,6 +2093,7 @@ int f2fs_gc_range(struct f2fs_sb_info *s + 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/queue-6.18/f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch b/queue-6.18/f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch new file mode 100644 index 0000000000..fab14065db --- /dev/null +++ b/queue-6.18/f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch @@ -0,0 +1,140 @@ +From 5c145c03188bc9ba1c29e0bc4d527a5978fc47f9 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Tue, 13 Jan 2026 14:22:29 +0800 +Subject: f2fs: fix to avoid mapping wrong physical block for swapfile + +From: Chao Yu + +commit 5c145c03188bc9ba1c29e0bc4d527a5978fc47f9 upstream. + +Xiaolong Guo reported a f2fs bug in bugzilla [1] + +[1] https://bugzilla.kernel.org/show_bug.cgi?id=220951 + +Quoted: + +"When using stress-ng's swap stress test on F2FS filesystem with kernel 6.6+, +the system experiences data corruption leading to either: +1 dm-verity corruption errors and device reboot +2 F2FS node corruption errors and boot hangs + +The issue occurs specifically when: +1 Using F2FS filesystem (ext4 is unaffected) +2 Swapfile size is less than F2FS section size (2MB) +3 Swapfile has fragmented physical layout (multiple non-contiguous extents) +4 Kernel version is 6.6+ (6.1 is unaffected) + +The root cause is in check_swap_activate() function in fs/f2fs/data.c. When the +first extent of a small swapfile (< 2MB) is not aligned to section boundaries, +the function incorrectly treats it as the last extent, failing to map +subsequent extents. This results in incorrect swap_extent creation where only +the first extent is mapped, causing subsequent swap writes to overwrite wrong +physical locations (other files' data). + +Steps to Reproduce +1 Setup a device with F2FS-formatted userdata partition +2 Compile stress-ng from https://github.com/ColinIanKing/stress-ng +3 Run swap stress test: (Android devices) +adb shell "cd /data/stressng; ./stress-ng-64 --metrics-brief --timeout 60 +--swap 0" + +Log: +1 Ftrace shows in kernel 6.6, only first extent is mapped during second +f2fs_map_blocks call in check_swap_activate(): +stress-ng-swap-8990: f2fs_map_blocks: ino=11002, file offset=0, start +blkaddr=0x43143, len=0x1 +(Only 4KB mapped, not the full swapfile) +2 in kernel 6.1, both extents are correctly mapped: +stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=0, start +blkaddr=0x13cd4, len=0x1 +stress-ng-swap-5966: f2fs_map_blocks: ino=28011, file offset=1, start +blkaddr=0x60c84b, len=0xff + +The problematic code is in check_swap_activate(): +if ((pblock - SM_I(sbi)->main_blkaddr) % blks_per_sec || + nr_pblocks % blks_per_sec || + !f2fs_valid_pinned_area(sbi, pblock)) { + bool last_extent = false; + + not_aligned++; + + nr_pblocks = roundup(nr_pblocks, blks_per_sec); + if (cur_lblock + nr_pblocks > sis->max) + nr_pblocks -= blks_per_sec; + + /* this extent is last one */ + if (!nr_pblocks) { + nr_pblocks = last_lblock - cur_lblock; + last_extent = true; + } + + ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks); + if (ret) { + if (ret == -ENOENT) + ret = -EINVAL; + goto out; + } + + if (!last_extent) + goto retry; +} + +When the first extent is unaligned and roundup(nr_pblocks, blks_per_sec) +exceeds sis->max, we subtract blks_per_sec resulting in nr_pblocks = 0. The +code then incorrectly assumes this is the last extent, sets nr_pblocks = +last_lblock - cur_lblock (entire swapfile), and performs migration. After +migration, it doesn't retry mapping, so subsequent extents are never processed. +" + +In order to fix this issue, we need to lookup block mapping info after +we migrate all blocks in the tail of swapfile. + +Cc: stable@kernel.org +Fixes: 9703d69d9d15 ("f2fs: support file pinning for zoned devices") +Cc: Daeho Jeong +Reported-and-tested-by: Xiaolong Guo +Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220951 +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -3939,6 +3939,7 @@ static int check_swap_activate(struct sw + + while (cur_lblock < last_lblock && cur_lblock < sis->max) { + struct f2fs_map_blocks map; ++ bool last_extent = false; + retry: + cond_resched(); + +@@ -3964,11 +3965,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); +@@ -3989,8 +3989,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) diff --git a/queue-6.18/f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch b/queue-6.18/f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch new file mode 100644 index 0000000000..34dd21913b --- /dev/null +++ b/queue-6.18/f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch @@ -0,0 +1,75 @@ +From ce2739e482bce8d2c014d76c4531c877f382aa54 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Wed, 7 Jan 2026 19:22:18 +0800 +Subject: f2fs: fix to avoid UAF in f2fs_write_end_io() + +From: Chao Yu + +commit ce2739e482bce8d2c014d76c4531c877f382aa54 upstream. + +As syzbot reported an use-after-free issue in f2fs_write_end_io(). + +It is caused by below race condition: + +loop device umount +- worker_thread + - loop_process_work + - do_req_filebacked + - lo_rw_aio + - lo_rw_aio_complete + - blk_mq_end_request + - blk_update_request + - f2fs_write_end_io + - dec_page_count + - folio_end_writeback + - kill_f2fs_super + - kill_block_super + - f2fs_put_super + : free(sbi) + : get_pages(, F2FS_WB_CP_DATA) + accessed sbi which is freed + +In kill_f2fs_super(), we will drop all page caches of f2fs inodes before +call free(sbi), it guarantee that all folios should end its writeback, so +it should be safe to access sbi before last folio_end_writeback(). + +Let's relocate ckpt thread wakeup flow before folio_end_writeback() to +resolve this issue. + +Cc: stable@kernel.org +Fixes: e234088758fc ("f2fs: avoid wait if IO end up when do_checkpoint for better performance") +Reported-by: syzbot+b4444e3c972a7a124187@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=b4444e3c972a7a124187 +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -356,14 +356,20 @@ static void f2fs_write_end_io(struct bio + 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); + } diff --git a/queue-6.18/f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch b/queue-6.18/f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch new file mode 100644 index 0000000000..87343fbde9 --- /dev/null +++ b/queue-6.18/f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch @@ -0,0 +1,32 @@ +From 0eda086de85e140f53c6123a4c00662f4e614ee4 Mon Sep 17 00:00:00 2001 +From: Chao Yu +Date: Tue, 6 Jan 2026 14:31:17 +0800 +Subject: f2fs: fix to check sysfs filename w/ gc_pin_file_thresh correctly + +From: Chao Yu + +commit 0eda086de85e140f53c6123a4c00662f4e614ee4 upstream. + +Sysfs entry name is gc_pin_file_thresh instead of gc_pin_file_threshold, +fix it. + +Cc: stable@kernel.org +Fixes: c521a6ab4ad7 ("f2fs: fix to limit gc_pin_file_threshold") +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/sysfs.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/f2fs/sysfs.c ++++ b/fs/f2fs/sysfs.c +@@ -749,7 +749,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; diff --git a/queue-6.18/f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch b/queue-6.18/f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch new file mode 100644 index 0000000000..40f539e99a --- /dev/null +++ b/queue-6.18/f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch @@ -0,0 +1,75 @@ +From d860974a7e38d35e9e2c4dc8a9f4223b38b6ad99 Mon Sep 17 00:00:00 2001 +From: Yeongjin Gil +Date: Thu, 22 Jan 2026 19:45:27 +0900 +Subject: f2fs: optimize f2fs_overwrite_io() for f2fs_iomap_begin + +From: Yeongjin Gil + +commit d860974a7e38d35e9e2c4dc8a9f4223b38b6ad99 upstream. + +When overwriting already allocated blocks, f2fs_iomap_begin() calls +f2fs_overwrite_io() to check block mappings. However, +f2fs_overwrite_io() iterates through all mapped blocks in the range, +which can be inefficient for fragmented files with large I/O requests. + +This patch optimizes f2fs_overwrite_io() by adding a 'check_first' +parameter and introducing __f2fs_overwrite_io() helper. When called from +f2fs_iomap_begin(), we only check the first mapping to determine if the +range is already allocated, which is sufficient for setting +map.m_may_create. + +This optimization significantly reduces the number of f2fs_map_blocks() +calls in f2fs_overwrite_io() when called from f2fs_iomap_begin(), +especially for fragmented files with large I/O requests. + +Cc: stable@kernel.org +Fixes: 351bc761338d ("f2fs: optimize f2fs DIO overwrites") +Reviewed-by: Sungjong Seo +Reviewed-by: Sunmin Jeong +Signed-off-by: Yeongjin Gil +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/data.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -1799,7 +1799,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; +@@ -1821,10 +1822,17 @@ bool f2fs_overwrite_io(struct inode *ino + 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) + { +@@ -4191,7 +4199,7 @@ static int f2fs_iomap_begin(struct inode + * 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/queue-6.18/f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch b/queue-6.18/f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch new file mode 100644 index 0000000000..616dbb60ab --- /dev/null +++ b/queue-6.18/f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch @@ -0,0 +1,721 @@ +From e48e16f3e37fac76e2f0c14c58df2b0398a323b0 Mon Sep 17 00:00:00 2001 +From: Daeho Jeong +Date: Sat, 10 Jan 2026 15:54:05 -0800 +Subject: f2fs: support non-4KB block size without packed_ssa feature + +From: Daeho Jeong + +commit e48e16f3e37fac76e2f0c14c58df2b0398a323b0 upstream. + +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: 7ee8bc3942f2 ("f2fs: revert summary entry count from 2048 to 512 in 16kb block support") +Signed-off-by: Daeho Jeong +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/f2fs.h | 52 ++++++++++++++++++++--------- + fs/f2fs/gc.c | 23 ++++++------ + fs/f2fs/node.c | 12 +++--- + fs/f2fs/recovery.c | 6 +-- + fs/f2fs/segment.c | 86 +++++++++++++++++++++++++----------------------- + fs/f2fs/segment.h | 9 ++--- + fs/f2fs/super.c | 26 ++++++-------- + include/linux/f2fs_fs.h | 73 +++++++++++++++++++++++++--------------- + 8 files changed, 165 insertions(+), 122 deletions(-) + +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -508,13 +508,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 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(jnl) (NAT_JOURNAL_ENTRIES - nats_in_cursum(jnl)) +-#define MAX_SIT_JENTRIES(jnl) (SIT_JOURNAL_ENTRIES - sits_in_cursum(jnl)) ++#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) + { +@@ -532,14 +544,6 @@ static inline int update_sits_in_cursum( + 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); +@@ -1750,6 +1754,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 */ +@@ -2799,6 +2812,14 @@ static inline block_t __start_sum_addr(s + 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) +@@ -3952,7 +3973,8 @@ void f2fs_wait_on_block_writeback_range( + 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); +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -1766,8 +1766,8 @@ static int do_garbage_collect(struct f2f + + 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), +@@ -1777,17 +1777,17 @@ static int do_garbage_collect(struct f2f + 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; + } +@@ -1803,8 +1803,8 @@ static int do_garbage_collect(struct f2f + /* 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; +@@ -1830,12 +1830,13 @@ static int do_garbage_collect(struct f2f + 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; +--- 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); +@@ -2943,7 +2943,7 @@ int f2fs_restore_node_summary(struct f2f + /* 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); +@@ -3084,7 +3084,7 @@ static int __flush_nat_entry_set(struct + * #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) { +@@ -3107,7 +3107,7 @@ static int __flush_nat_entry_set(struct + 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); +@@ -3178,7 +3178,7 @@ int f2fs_flush_nat_entries(struct f2fs_s + * 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); + +@@ -3189,7 +3189,7 @@ int f2fs_flush_nat_entries(struct f2fs_s + 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 */ +--- a/fs/f2fs/recovery.c ++++ b/fs/f2fs/recovery.c +@@ -514,7 +514,7 @@ static int check_index_in_prev_nodes(str + 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(str + 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 */ +--- a/fs/f2fs/segment.c ++++ b/fs/f2fs/segment.c +@@ -2689,12 +2689,12 @@ int f2fs_npages_for_summary_flush(struct + 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; + 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->sum_blocksize - SUM_FOOTER_SIZE) / SUMMARY_SIZE) + return 2; + return 3; + } +@@ -2714,7 +2714,7 @@ void f2fs_update_meta_page(struct f2fs_s + { + 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); +@@ -2732,7 +2732,7 @@ static void write_sum_page(struct f2fs_s + { + 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)); + +@@ -2740,7 +2740,8 @@ static void write_sum_page(struct f2fs_s + 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); + } +@@ -2759,11 +2760,11 @@ static void write_current_sum_page(struc + 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); + +@@ -2936,7 +2937,7 @@ static void reset_curseg(struct f2fs_sb_ + 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); +@@ -3082,11 +3083,11 @@ static int change_curseg(struct f2fs_sb_ + 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; + } +@@ -3818,7 +3819,7 @@ int f2fs_allocate_data_block(struct f2fs + + 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 { +@@ -4187,7 +4188,7 @@ void f2fs_do_replace_block(struct f2fs_s + } + + 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) +@@ -4307,12 +4308,12 @@ static int read_compacted_summaries(stru + + /* 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++) { +@@ -4334,9 +4335,9 @@ static int read_compacted_summaries(stru + 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->sum_blocksize - + SUM_FOOTER_SIZE) + continue; + +@@ -4392,7 +4393,7 @@ static int read_normal_summaries(struct + + 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++) { +@@ -4412,11 +4413,13 @@ static int read_normal_summaries(struct + + /* 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]; +@@ -4460,8 +4463,8 @@ static int restore_curseg_summaries(stru + } + + /* 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; +@@ -4485,13 +4488,13 @@ static void write_compacted_summaries(st + + /* 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++) { +@@ -4504,7 +4507,7 @@ static void write_compacted_summaries(st + 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 - +@@ -4549,8 +4552,9 @@ void f2fs_write_node_summaries(struct f2 + 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; + +@@ -4559,13 +4563,13 @@ int f2fs_lookup_journal_in_cursum(struct + 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; +@@ -4713,8 +4717,8 @@ void f2fs_flush_sit_entries(struct f2fs_ + * 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); + + /* +@@ -4731,7 +4735,8 @@ void f2fs_flush_sit_entries(struct f2fs_ + 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) { +@@ -4759,7 +4764,7 @@ void f2fs_flush_sit_entries(struct f2fs_ + } + + 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) = +@@ -4966,12 +4971,13 @@ static int build_curseg(struct f2fs_sb_i + + 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); +--- a/fs/f2fs/segment.h ++++ b/fs/f2fs/segment.h +@@ -85,12 +85,11 @@ static inline void sanity_check_seg_type + #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)) +--- a/fs/f2fs/super.c ++++ b/fs/f2fs/super.c +@@ -4059,20 +4059,6 @@ static int sanity_check_raw_super(struct + 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; + } + +@@ -4283,6 +4269,18 @@ static void init_sb_info(struct f2fs_sb_ + 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; +--- 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; + + /* diff --git a/queue-6.18/fbdev-rivafb-fix-divide-error-in-nv3_arb.patch b/queue-6.18/fbdev-rivafb-fix-divide-error-in-nv3_arb.patch new file mode 100644 index 0000000000..508d7baab6 --- /dev/null +++ b/queue-6.18/fbdev-rivafb-fix-divide-error-in-nv3_arb.patch @@ -0,0 +1,65 @@ +From 0209e21e3c372fa2da04c39214bec0b64e4eb5f4 Mon Sep 17 00:00:00 2001 +From: Guangshuo Li +Date: Sun, 7 Dec 2025 15:25:32 +0800 +Subject: fbdev: rivafb: fix divide error in nv3_arb() + +From: Guangshuo Li + +commit 0209e21e3c372fa2da04c39214bec0b64e4eb5f4 upstream. + +A userspace program can trigger the RIVA NV3 arbitration code by calling +the FBIOPUT_VSCREENINFO ioctl on /dev/fb*. When doing so, the driver +recomputes FIFO arbitration parameters in nv3_arb(), using state->mclk_khz +(derived from the PRAMDAC MCLK PLL) as a divisor without validating it +first. + +In a normal setup, state->mclk_khz is provided by the real hardware and is +non-zero. However, an attacker can construct a malicious or misconfigured +device (e.g. a crafted/emulated PCI device) that exposes a bogus PLL +configuration, causing state->mclk_khz to become zero. Once +nv3_get_param() calls nv3_arb(), the division by state->mclk_khz in the gns +calculation causes a divide error and crashes the kernel. + +Fix this by checking whether state->mclk_khz is zero and bailing out before +doing the division. + +The following log reveals it: + +rivafb: setting virtual Y resolution to 2184 +divide error: 0000 [#1] PREEMPT SMP KASAN PTI +CPU: 0 PID: 2187 Comm: syz-executor.0 Not tainted 5.18.0-rc1+ #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 +RIP: 0010:nv3_arb drivers/video/fbdev/riva/riva_hw.c:439 [inline] +RIP: 0010:nv3_get_param+0x3ab/0x13b0 drivers/video/fbdev/riva/riva_hw.c:546 +Call Trace: + nv3CalcArbitration.constprop.0+0x255/0x460 drivers/video/fbdev/riva/riva_hw.c:603 + nv3UpdateArbitrationSettings drivers/video/fbdev/riva/riva_hw.c:637 [inline] + CalcStateExt+0x447/0x1b90 drivers/video/fbdev/riva/riva_hw.c:1246 + riva_load_video_mode+0x8a9/0xea0 drivers/video/fbdev/riva/fbdev.c:779 + rivafb_set_par+0xc0/0x5f0 drivers/video/fbdev/riva/fbdev.c:1196 + fb_set_var+0x604/0xeb0 drivers/video/fbdev/core/fbmem.c:1033 + do_fb_ioctl+0x234/0x670 drivers/video/fbdev/core/fbmem.c:1109 + fb_ioctl+0xdd/0x130 drivers/video/fbdev/core/fbmem.c:1188 + __x64_sys_ioctl+0x122/0x190 fs/ioctl.c:856 + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Guangshuo Li +Signed-off-by: Helge Deller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/video/fbdev/riva/riva_hw.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- 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_ + 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/queue-6.18/fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch b/queue-6.18/fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch new file mode 100644 index 0000000000..558b7db8cc --- /dev/null +++ b/queue-6.18/fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch @@ -0,0 +1,57 @@ +From 120adae7b42faa641179270c067864544a50ab69 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Sun, 28 Dec 2025 14:17:03 +0100 +Subject: fbdev: smscufx: properly copy ioctl memory to kernelspace + +From: Greg Kroah-Hartman + +commit 120adae7b42faa641179270c067864544a50ab69 upstream. + +The UFX_IOCTL_REPORT_DAMAGE ioctl does not properly copy data from +userspace to kernelspace, and instead directly references the memory, +which can cause problems if invalid data is passed from userspace. Fix +this all up by correctly copying the memory before accessing it within +the kernel. + +Reported-by: Tianchu Chen +Cc: stable +Cc: Steve Glendinning +Cc: Helge Deller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Helge Deller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/video/fbdev/smscufx.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/video/fbdev/smscufx.c ++++ b/drivers/video/fbdev/smscufx.c +@@ -932,7 +932,6 @@ static int ufx_ops_ioctl(struct fb_info + 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 + + /* 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 + 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/queue-6.18/series b/queue-6.18/series index eaf2cf2fa7..dd5562eda4 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -27,3 +27,13 @@ arm64-dts-mediatek-mt8183-add-missing-endpoint-ids-to-display-graph.patch mm-hugetlb-fix-excessive-ipi-broadcasts-when-unsharing-pmd-tables-using-mmu_gather.patch loongarch-rework-kasan-initialization-for-ptw-enabled-systems.patch cpuset-fix-missing-adaptation-for-cpuset_is_populated.patch +fbdev-rivafb-fix-divide-error-in-nv3_arb.patch +fbdev-smscufx-properly-copy-ioctl-memory-to-kernelspace.patch +f2fs-fix-to-add-gc-count-stat-in-f2fs_gc_range.patch +f2fs-fix-to-check-sysfs-filename-w-gc_pin_file_thresh-correctly.patch +f2fs-fix-is_checkpointed-flag-inconsistency-issue-caused-by-concurrent-atomic-commit-and-checkpoint-writes.patch +f2fs-fix-out-of-bounds-access-in-sysfs-attribute-read-write.patch +f2fs-fix-to-avoid-uaf-in-f2fs_write_end_io.patch +f2fs-support-non-4kb-block-size-without-packed_ssa-feature.patch +f2fs-fix-to-avoid-mapping-wrong-physical-block-for-swapfile.patch +f2fs-optimize-f2fs_overwrite_io-for-f2fs_iomap_begin.patch -- 2.47.3