+++ /dev/null
-From 891520a1e9d657d51327e792f782dc5421ca1cd3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 27 Jan 2022 13:31:43 -0800
-Subject: f2fs: add a way to limit roll forward recovery time
-
-From: Jaegeuk Kim <jaegeuk@kernel.org>
-
-[ Upstream commit 47c8ebcce85ed7113e9e3e3f1d8c6374fa87848e ]
-
-This adds a sysfs entry to call checkpoint during fsync() in order to avoid
-long elapsed time to run roll-forward recovery when booting the device.
-Default value doesn't enforce the limitation which is same as before.
-
-Reviewed-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Stable-dep-of: f06c0f82e38b ("f2fs: fix to update user block counts in block_operations()")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- Documentation/ABI/testing/sysfs-fs-f2fs | 6 ++++++
- fs/f2fs/checkpoint.c | 1 +
- fs/f2fs/debug.c | 3 +++
- fs/f2fs/f2fs.h | 3 +++
- fs/f2fs/node.c | 2 ++
- fs/f2fs/node.h | 3 +++
- fs/f2fs/recovery.c | 4 ++++
- fs/f2fs/super.c | 14 ++++++++++++--
- fs/f2fs/sysfs.c | 2 ++
- 9 files changed, 36 insertions(+), 2 deletions(-)
-
-diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
-index bdbece0b08051..92bc2bdc8baf1 100644
---- a/Documentation/ABI/testing/sysfs-fs-f2fs
-+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
-@@ -536,3 +536,9 @@ Contact: "Daeho Jeong" <daehojeong@google.com>
- Description: You can set the trial count limit for GC urgent high mode with this value.
- If GC thread gets to the limit, the mode will turn back to GC normal mode.
- By default, the value is zero, which means there is no limit like before.
-+
-+What: /sys/fs/f2fs/<disk>/max_roll_forward_node_blocks
-+Date: January 2022
-+Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
-+Description: Controls max # of node block writes to be used for roll forward
-+ recovery. This can limit the roll forward recovery time.
-diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
-index 71a3714419f85..8d12e2fa32b8f 100644
---- a/fs/f2fs/checkpoint.c
-+++ b/fs/f2fs/checkpoint.c
-@@ -1569,6 +1569,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- /* update user_block_counts */
- sbi->last_valid_block_count = sbi->total_valid_block_count;
- percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-+ percpu_counter_set(&sbi->rf_node_block_count, 0);
-
- /* Here, we have one bio having CP pack except cp pack 2 page */
- f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
-diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
-index b449c7a372a4b..6d26872c7364d 100644
---- a/fs/f2fs/debug.c
-+++ b/fs/f2fs/debug.c
-@@ -534,6 +534,9 @@ static int stat_show(struct seq_file *s, void *v)
- si->ndirty_meta, si->meta_pages);
- seq_printf(s, " - imeta: %4d\n",
- si->ndirty_imeta);
-+ seq_printf(s, " - fsync mark: %4lld\n",
-+ percpu_counter_sum_positive(
-+ &si->sbi->rf_node_block_count));
- seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
- si->dirty_nats, si->nats, si->dirty_sits, si->sits);
- seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n",
-diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
-index d4a5700927cd5..fb1422a81d382 100644
---- a/fs/f2fs/f2fs.h
-+++ b/fs/f2fs/f2fs.h
-@@ -891,6 +891,7 @@ struct f2fs_nm_info {
- nid_t max_nid; /* maximum possible node ids */
- nid_t available_nids; /* # of available node ids */
- nid_t next_scan_nid; /* the next nid to be scanned */
-+ nid_t max_rf_node_blocks; /* max # of nodes for recovery */
- unsigned int ram_thresh; /* control the memory footprint */
- unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */
- unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */
-@@ -1663,6 +1664,8 @@ struct f2fs_sb_info {
- atomic_t nr_pages[NR_COUNT_TYPE];
- /* # of allocated blocks */
- struct percpu_counter alloc_valid_block_count;
-+ /* # of node block writes as roll forward recovery */
-+ struct percpu_counter rf_node_block_count;
-
- /* writeback control */
- atomic_t wb_sync_req[META]; /* count # of WB_SYNC threads */
-diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
-index b6758887540f2..16eab673ca84d 100644
---- a/fs/f2fs/node.c
-+++ b/fs/f2fs/node.c
-@@ -1787,6 +1787,7 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
-
- if (!atomic || page == last_page) {
- set_fsync_mark(page, 1);
-+ percpu_counter_inc(&sbi->rf_node_block_count);
- if (IS_INODE(page)) {
- if (is_inode_flag_set(inode,
- FI_DIRTY_INODE))
-@@ -3227,6 +3228,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
- nm_i->ram_thresh = DEF_RAM_THRESHOLD;
- nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
- nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD;
-+ nm_i->max_rf_node_blocks = DEF_RF_NODE_BLOCKS;
-
- INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
- INIT_LIST_HEAD(&nm_i->free_nid_list);
-diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
-index ff14a6e5ac1c9..048f309e32ff4 100644
---- a/fs/f2fs/node.h
-+++ b/fs/f2fs/node.h
-@@ -31,6 +31,9 @@
- /* control total # of nats */
- #define DEF_NAT_CACHE_THRESHOLD 100000
-
-+/* control total # of node writes used for roll-fowrad recovery */
-+#define DEF_RF_NODE_BLOCKS 0
-+
- /* vector size for gang look-up from nat cache that consists of radix tree */
- #define NATVEC_SIZE 64
- #define SETVEC_SIZE 32
-diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
-index f07ae58d266d1..a5044be137988 100644
---- a/fs/f2fs/recovery.c
-+++ b/fs/f2fs/recovery.c
-@@ -55,6 +55,10 @@ bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi)
-
- if (sbi->last_valid_block_count + nalloc > sbi->user_block_count)
- return false;
-+ if (NM_I(sbi)->max_rf_node_blocks &&
-+ percpu_counter_sum_positive(&sbi->rf_node_block_count) >=
-+ NM_I(sbi)->max_rf_node_blocks)
-+ return false;
- return true;
- }
-
-diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
-index 098daef550f49..144c35b2760f4 100644
---- a/fs/f2fs/super.c
-+++ b/fs/f2fs/super.c
-@@ -1540,8 +1540,9 @@ static void f2fs_free_inode(struct inode *inode)
-
- static void destroy_percpu_info(struct f2fs_sb_info *sbi)
- {
-- percpu_counter_destroy(&sbi->alloc_valid_block_count);
- percpu_counter_destroy(&sbi->total_valid_inode_count);
-+ percpu_counter_destroy(&sbi->rf_node_block_count);
-+ percpu_counter_destroy(&sbi->alloc_valid_block_count);
- }
-
- static void destroy_device_list(struct f2fs_sb_info *sbi)
-@@ -3659,11 +3660,20 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
- if (err)
- return err;
-
-+ err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL);
-+ if (err)
-+ goto err_valid_block;
-+
- err = percpu_counter_init(&sbi->total_valid_inode_count, 0,
- GFP_KERNEL);
- if (err)
-- percpu_counter_destroy(&sbi->alloc_valid_block_count);
-+ goto err_node_block;
-+ return 0;
-
-+err_node_block:
-+ percpu_counter_destroy(&sbi->rf_node_block_count);
-+err_valid_block:
-+ percpu_counter_destroy(&sbi->alloc_valid_block_count);
- return err;
- }
-
-diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
-index 673b1153dbc67..5bccd70a3f3be 100644
---- a/fs/f2fs/sysfs.c
-+++ b/fs/f2fs/sysfs.c
-@@ -720,6 +720,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections);
- F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
- F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
- F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
-+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, max_roll_forward_node_blocks, max_rf_node_blocks);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, migration_granularity, migration_granularity);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
-@@ -837,6 +838,7 @@ static struct attribute *f2fs_attrs[] = {
- ATTR_LIST(ram_thresh),
- ATTR_LIST(ra_nid_pages),
- ATTR_LIST(dirty_nats_ratio),
-+ ATTR_LIST(max_roll_forward_node_blocks),
- ATTR_LIST(cp_interval),
- ATTR_LIST(idle_interval),
- ATTR_LIST(discard_idle_interval),
---
-2.43.0
-
+++ /dev/null
-From 6d0fb871dbe1cd210304a6833e845a4f1c5cfb27 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 8 Dec 2021 16:41:51 -0800
-Subject: f2fs: add gc_urgent_high_remaining sysfs node
-
-From: Daeho Jeong <daehojeong@google.com>
-
-[ Upstream commit 325163e9892b627fc9fb1af51e51f0f95dded517 ]
-
-Added a new sysfs node called gc_urgent_high_remaining. The user can
-set the trial count limit for GC urgent high mode with this value. If
-GC thread gets to the limit, the mode will turn back to GC normal mode.
-By default, the value is zero, which means there is no limit like before.
-
-Signed-off-by: Daeho Jeong <daehojeong@google.com>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Stable-dep-of: f06c0f82e38b ("f2fs: fix to update user block counts in block_operations()")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- Documentation/ABI/testing/sysfs-fs-f2fs | 7 +++++++
- fs/f2fs/f2fs.h | 3 +++
- fs/f2fs/gc.c | 12 ++++++++++++
- fs/f2fs/super.c | 1 +
- fs/f2fs/sysfs.c | 11 +++++++++++
- 5 files changed, 34 insertions(+)
-
-diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
-index 91e2b549f8172..bdbece0b08051 100644
---- a/Documentation/ABI/testing/sysfs-fs-f2fs
-+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
-@@ -529,3 +529,10 @@ Description: With "mode=fragment:block" mount options, we can scatter block allo
- f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
- in the length of 1..<max_fragment_hole> by turns. This value can be set
- between 1..512 and the default value is 4.
-+
-+What: /sys/fs/f2fs/<disk>/gc_urgent_high_remaining
-+Date: December 2021
-+Contact: "Daeho Jeong" <daehojeong@google.com>
-+Description: You can set the trial count limit for GC urgent high mode with this value.
-+ If GC thread gets to the limit, the mode will turn back to GC normal mode.
-+ By default, the value is zero, which means there is no limit like before.
-diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
-index b5f1099ab388f..d4a5700927cd5 100644
---- a/fs/f2fs/f2fs.h
-+++ b/fs/f2fs/f2fs.h
-@@ -1682,6 +1682,9 @@ struct f2fs_sb_info {
- unsigned int cur_victim_sec; /* current victim section num */
- unsigned int gc_mode; /* current GC state */
- unsigned int next_victim_seg[2]; /* next segment in victim section */
-+ spinlock_t gc_urgent_high_lock;
-+ bool gc_urgent_high_limited; /* indicates having limited trial count */
-+ unsigned int gc_urgent_high_remaining; /* remaining trial count for GC_URGENT_HIGH */
-
- /* for skip statistic */
- unsigned int atomic_files; /* # of opened atomic file */
-diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
-index 4d4d7f0c8a71b..21081e7ff55d5 100644
---- a/fs/f2fs/gc.c
-+++ b/fs/f2fs/gc.c
-@@ -92,6 +92,18 @@ static int gc_thread_func(void *data)
- * So, I'd like to wait some time to collect dirty segments.
- */
- if (sbi->gc_mode == GC_URGENT_HIGH) {
-+ spin_lock(&sbi->gc_urgent_high_lock);
-+ if (sbi->gc_urgent_high_limited) {
-+ if (!sbi->gc_urgent_high_remaining) {
-+ sbi->gc_urgent_high_limited = false;
-+ spin_unlock(&sbi->gc_urgent_high_lock);
-+ sbi->gc_mode = GC_NORMAL;
-+ continue;
-+ }
-+ sbi->gc_urgent_high_remaining--;
-+ }
-+ spin_unlock(&sbi->gc_urgent_high_lock);
-+
- wait_ms = gc_th->urgent_sleep_time;
- down_write(&sbi->gc_lock);
- goto do_gc;
-diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
-index 339e44467b9cd..098daef550f49 100644
---- a/fs/f2fs/super.c
-+++ b/fs/f2fs/super.c
-@@ -3621,6 +3621,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
- sbi->seq_file_ra_mul = MIN_RA_MUL;
- sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
- sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
-+ spin_lock_init(&sbi->gc_urgent_high_lock);
-
- sbi->dir_level = DEF_DIR_LEVEL;
- sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
-diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
-index c0e72bd44b135..673b1153dbc67 100644
---- a/fs/f2fs/sysfs.c
-+++ b/fs/f2fs/sysfs.c
-@@ -480,6 +480,15 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
- return count;
- }
-
-+ if (!strcmp(a->attr.name, "gc_urgent_high_remaining")) {
-+ spin_lock(&sbi->gc_urgent_high_lock);
-+ sbi->gc_urgent_high_limited = t == 0 ? false : true;
-+ sbi->gc_urgent_high_remaining = t;
-+ spin_unlock(&sbi->gc_urgent_high_lock);
-+
-+ return count;
-+ }
-+
- #ifdef CONFIG_F2FS_IOSTAT
- if (!strcmp(a->attr.name, "iostat_enable")) {
- sbi->iostat_enable = !!t;
-@@ -735,6 +744,7 @@ F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
- #endif
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag);
-+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent_high_remaining, gc_urgent_high_remaining);
- F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio);
- F2FS_GENERAL_RO_ATTR(dirty_segments);
- F2FS_GENERAL_RO_ATTR(free_segments);
-@@ -846,6 +856,7 @@ static struct attribute *f2fs_attrs[] = {
- #endif
- ATTR_LIST(data_io_flag),
- ATTR_LIST(node_io_flag),
-+ ATTR_LIST(gc_urgent_high_remaining),
- ATTR_LIST(ckpt_thread_ioprio),
- ATTR_LIST(dirty_segments),
- ATTR_LIST(free_segments),
---
-2.43.0
-
+++ /dev/null
-From fce24e07ef388141ce18a9fcc5cc4e5bcc05dc42 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 18 Jun 2024 02:15:38 +0000
-Subject: f2fs: assign CURSEG_ALL_DATA_ATGC if blkaddr is valid
-
-From: Jaegeuk Kim <jaegeuk@kernel.org>
-
-[ Upstream commit 8cb1f4080dd91c6e6b01dbea013a3f42341cb6a1 ]
-
-mkdir /mnt/test/comp
-f2fs_io setflags compression /mnt/test/comp
-dd if=/dev/zero of=/mnt/test/comp/testfile bs=16k count=1
-truncate --size 13 /mnt/test/comp/testfile
-
-In the above scenario, we can get a BUG_ON.
- kernel BUG at fs/f2fs/segment.c:3589!
- Call Trace:
- do_write_page+0x78/0x390 [f2fs]
- f2fs_outplace_write_data+0x62/0xb0 [f2fs]
- f2fs_do_write_data_page+0x275/0x740 [f2fs]
- f2fs_write_single_data_page+0x1dc/0x8f0 [f2fs]
- f2fs_write_multi_pages+0x1e5/0xae0 [f2fs]
- f2fs_write_cache_pages+0xab1/0xc60 [f2fs]
- f2fs_write_data_pages+0x2d8/0x330 [f2fs]
- do_writepages+0xcf/0x270
- __writeback_single_inode+0x44/0x350
- writeback_sb_inodes+0x242/0x530
- __writeback_inodes_wb+0x54/0xf0
- wb_writeback+0x192/0x310
- wb_workfn+0x30d/0x400
-
-The reason is we gave CURSEG_ALL_DATA_ATGC to COMPR_ADDR where the
-page was set the gcing flag by set_cluster_dirty().
-
-Cc: stable@vger.kernel.org
-Fixes: 4961acdd65c9 ("f2fs: fix to tag gcing flag on page during block migration")
-Reviewed-by: Chao Yu <chao@kernel.org>
-Tested-by: Will McVicker <willmcvicker@google.com>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/f2fs/segment.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
-index d8b1980df52d6..ae70e536bef37 100644
---- a/fs/f2fs/segment.c
-+++ b/fs/f2fs/segment.c
-@@ -3360,6 +3360,7 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
- if (fio->sbi->am.atgc_enabled &&
- (fio->io_type == FS_DATA_IO) &&
- (fio->sbi->gc_mode != GC_URGENT_HIGH) &&
-+ __is_valid_data_blkaddr(fio->old_blkaddr) &&
- !is_inode_flag_set(inode, FI_OPU_WRITE))
- return CURSEG_ALL_DATA_ATGC;
- else
---
-2.43.0
-
+++ /dev/null
-From 42507285d0900ef65a62dc3aef2b194073593961 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 8 Jul 2024 20:04:07 +0800
-Subject: f2fs: fix start segno of large section
-
-From: Sheng Yong <shengyong@oppo.com>
-
-[ Upstream commit 8c409989678e92e4a737e7cd2bb04f3efb81071a ]
-
-get_ckpt_valid_blocks() checks valid ckpt blocks in current section.
-It counts all vblocks from the first to the last segment in the
-large section. However, START_SEGNO() is used to get the first segno
-in an SIT block. This patch fixes that to get the correct start segno.
-
-Fixes: 61461fc921b7 ("f2fs: fix to avoid touching checkpointed data in get_victim()")
-Signed-off-by: Sheng Yong <shengyong@oppo.com>
-Reviewed-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/f2fs/segment.h | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
-index 04f448ddf49ea..1d16449089d02 100644
---- a/fs/f2fs/segment.h
-+++ b/fs/f2fs/segment.h
-@@ -369,7 +369,8 @@ static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi,
- unsigned int segno, bool use_section)
- {
- if (use_section && __is_large_section(sbi)) {
-- unsigned int start_segno = START_SEGNO(segno);
-+ unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
-+ unsigned int start_segno = GET_SEG_FROM_SEC(sbi, secno);
- unsigned int blocks = 0;
- int i;
-
---
-2.43.0
-
+++ /dev/null
-From f73481308a0fbe8393969f8daa0d85943a0dd576 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 29 May 2024 17:47:00 +0800
-Subject: f2fs: fix to avoid use SSR allocate when do defragment
-
-From: Zhiguo Niu <zhiguo.niu@unisoc.com>
-
-[ Upstream commit 21327a042dd94bc73181d7300e688699cb1f467e ]
-
-SSR allocate mode will be used when doing file defragment
-if ATGC is working at the same time, that is because
-set_page_private_gcing may make CURSEG_ALL_DATA_ATGC segment
-type got in f2fs_allocate_data_block when defragment page
-is writeback, which may cause file fragmentation is worse.
-
-A file with 2 fragmentations is changed as following after defragment:
-
-----------------file info-------------------
-sensorsdata :
---------------------------------------------
-dev [254:48]
-ino [0x 3029 : 12329]
-mode [0x 81b0 : 33200]
-nlink [0x 1 : 1]
-uid [0x 27e6 : 10214]
-gid [0x 27e6 : 10214]
-size [0x 242000 : 2367488]
-blksize [0x 1000 : 4096]
-blocks [0x 1210 : 4624]
---------------------------------------------
-
-file_pos start_blk end_blk blks
- 0 11361121 11361207 87
- 356352 11361215 11361216 2
- 364544 11361218 11361218 1
- 368640 11361220 11361221 2
- 376832 11361224 11361225 2
- 385024 11361227 11361238 12
- 434176 11361240 11361252 13
- 487424 11361254 11361254 1
- 491520 11361271 11361279 9
- 528384 3681794 3681795 2
- 536576 3681797 3681797 1
- 540672 3681799 3681799 1
- 544768 3681803 3681803 1
- 548864 3681805 3681805 1
- 552960 3681807 3681807 1
- 557056 3681809 3681809 1
-
-Signed-off-by: Zhiguo Niu <zhiguo.niu@unisoc.com>
-Reviewed-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Stable-dep-of: 8cb1f4080dd9 ("f2fs: assign CURSEG_ALL_DATA_ATGC if blkaddr is valid")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/f2fs/segment.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
-index b059b02fc179d..d8b1980df52d6 100644
---- a/fs/f2fs/segment.c
-+++ b/fs/f2fs/segment.c
-@@ -3359,7 +3359,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
- if (page_private_gcing(fio->page)) {
- if (fio->sbi->am.atgc_enabled &&
- (fio->io_type == FS_DATA_IO) &&
-- (fio->sbi->gc_mode != GC_URGENT_HIGH))
-+ (fio->sbi->gc_mode != GC_URGENT_HIGH) &&
-+ !is_inode_flag_set(inode, FI_OPU_WRITE))
- return CURSEG_ALL_DATA_ATGC;
- else
- return CURSEG_COLD_DATA;
---
-2.43.0
-
+++ /dev/null
-From 28a1435984b58374df33937baf30b25d7668f3b4 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 25 Jun 2024 10:32:39 +0800
-Subject: f2fs: fix to update user block counts in block_operations()
-
-From: Chao Yu <chao@kernel.org>
-
-[ Upstream commit f06c0f82e38bbda7264d6ef3c90045ad2810e0f3 ]
-
-Commit 59c9081bc86e ("f2fs: allow write page cache when writting cp")
-allows write() to write data to page cache during checkpoint, so block
-count fields like .total_valid_block_count, .alloc_valid_block_count
-and .rf_node_block_count may encounter race condition as below:
-
-CP Thread A
-- write_checkpoint
- - block_operations
- - f2fs_down_write(&sbi->node_change)
- - __prepare_cp_block
- : ckpt->valid_block_count = .total_valid_block_count
- - f2fs_up_write(&sbi->node_change)
- - write
- - f2fs_preallocate_blocks
- - f2fs_map_blocks(,F2FS_GET_BLOCK_PRE_AIO)
- - f2fs_map_lock
- - f2fs_down_read(&sbi->node_change)
- - f2fs_reserve_new_blocks
- - inc_valid_block_count
- : percpu_counter_add(&sbi->alloc_valid_block_count, count)
- : sbi->total_valid_block_count += count
- - f2fs_up_read(&sbi->node_change)
- - do_checkpoint
- : sbi->last_valid_block_count = sbi->total_valid_block_count
- : percpu_counter_set(&sbi->alloc_valid_block_count, 0)
- : percpu_counter_set(&sbi->rf_node_block_count, 0)
- - fsync
- - need_do_checkpoint
- - f2fs_space_for_roll_forward
- : alloc_valid_block_count was reset to zero,
- so, it may missed last data during checkpoint
-
-Let's change to update .total_valid_block_count, .alloc_valid_block_count
-and .rf_node_block_count in block_operations(), then their access can be
-protected by .node_change and .cp_rwsem lock, so that it can avoid above
-race condition.
-
-Fixes: 59c9081bc86e ("f2fs: allow write page cache when writting cp")
-Cc: Yunlei He <heyunlei@oppo.com>
-Signed-off-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- fs/f2fs/checkpoint.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
-index 8d12e2fa32b8f..ab91aa0003fe4 100644
---- a/fs/f2fs/checkpoint.c
-+++ b/fs/f2fs/checkpoint.c
-@@ -1175,6 +1175,11 @@ static void __prepare_cp_block(struct f2fs_sb_info *sbi)
- ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
- ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
- ckpt->next_free_nid = cpu_to_le32(last_nid);
-+
-+ /* update user_block_counts */
-+ sbi->last_valid_block_count = sbi->total_valid_block_count;
-+ percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-+ percpu_counter_set(&sbi->rf_node_block_count, 0);
- }
-
- static bool __need_flush_quota(struct f2fs_sb_info *sbi)
-@@ -1566,11 +1571,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- start_blk += NR_CURSEG_NODE_TYPE;
- }
-
-- /* update user_block_counts */
-- sbi->last_valid_block_count = sbi->total_valid_block_count;
-- percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-- percpu_counter_set(&sbi->rf_node_block_count, 0);
--
- /* Here, we have one bio having CP pack except cp pack 2 page */
- f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
- /* Wait for all dirty meta pages to be submitted for IO */
---
-2.43.0
-
+++ /dev/null
-From 605b0a778aa2599aa902ae639b8e9937c74b869b Mon Sep 17 00:00:00 2001
-From: Jaegeuk Kim <jaegeuk@kernel.org>
-Date: Fri, 12 Aug 2022 22:49:50 -0700
-Subject: f2fs: fix wrong continue condition in GC
-
-From: Jaegeuk Kim <jaegeuk@kernel.org>
-
-commit 605b0a778aa2599aa902ae639b8e9937c74b869b upstream.
-
-We should decrease the frozen counter.
-
-Cc: stable@vger.kernel.org
-Fixes: 325163e9892b ("f2fs: add gc_urgent_high_remaining sysfs node")
-Reviewed-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- fs/f2fs/gc.c | 12 ++++--------
- 1 file changed, 4 insertions(+), 8 deletions(-)
-
---- a/fs/f2fs/gc.c
-+++ b/fs/f2fs/gc.c
-@@ -93,14 +93,10 @@ static int gc_thread_func(void *data)
- */
- if (sbi->gc_mode == GC_URGENT_HIGH) {
- spin_lock(&sbi->gc_urgent_high_lock);
-- if (sbi->gc_urgent_high_limited) {
-- if (!sbi->gc_urgent_high_remaining) {
-- sbi->gc_urgent_high_limited = false;
-- spin_unlock(&sbi->gc_urgent_high_lock);
-- sbi->gc_mode = GC_NORMAL;
-- continue;
-- }
-- sbi->gc_urgent_high_remaining--;
-+ if (sbi->gc_urgent_high_limited &&
-+ !sbi->gc_urgent_high_remaining--) {
-+ sbi->gc_urgent_high_limited = false;
-+ sbi->gc_mode = GC_NORMAL;
- }
- spin_unlock(&sbi->gc_urgent_high_lock);
-
+++ /dev/null
-From 73bca3a74464453640ea4a8e3aff8f475fcfdbab Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 4 Feb 2022 15:19:46 +0800
-Subject: f2fs: introduce F2FS_IPU_HONOR_OPU_WRITE ipu policy
-
-From: Chao Yu <chao@kernel.org>
-
-[ Upstream commit 1018a5463a063715365784704c4e8cdf2eec4b04 ]
-
-Once F2FS_IPU_FORCE policy is enabled in some cases:
-a) f2fs forces to use F2FS_IPU_FORCE in a small-sized volume
-b) user sets F2FS_IPU_FORCE policy via sysfs
-
-Then we may fail to defragment file due to IPU policy check, it doesn't
-make sense, let's introduce a new IPU policy to allow OPU during file
-defragmentation.
-
-In small-sized volume, let's enable F2FS_IPU_HONOR_OPU_WRITE policy
-by default.
-
-Signed-off-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Stable-dep-of: 8cb1f4080dd9 ("f2fs: assign CURSEG_ALL_DATA_ATGC if blkaddr is valid")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- Documentation/ABI/testing/sysfs-fs-f2fs | 3 ++-
- fs/f2fs/data.c | 18 +++++++++++++-----
- fs/f2fs/f2fs.h | 3 ++-
- fs/f2fs/file.c | 18 +++++++++++-------
- fs/f2fs/segment.h | 5 ++++-
- fs/f2fs/super.c | 3 ++-
- 6 files changed, 34 insertions(+), 16 deletions(-)
-
-diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
-index 92bc2bdc8baf1..320fc162bcf15 100644
---- a/Documentation/ABI/testing/sysfs-fs-f2fs
-+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
-@@ -55,8 +55,9 @@ Description: Controls the in-place-update policy.
- 0x04 F2FS_IPU_UTIL
- 0x08 F2FS_IPU_SSR_UTIL
- 0x10 F2FS_IPU_FSYNC
-- 0x20 F2FS_IPU_ASYNC,
-+ 0x20 F2FS_IPU_ASYNC
- 0x40 F2FS_IPU_NOCACHE
-+ 0x80 F2FS_IPU_HONOR_OPU_WRITE
- ==== =================
-
- Refer segment.h for details.
-diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
-index fa86eaf1d6393..3f8dae229d422 100644
---- a/fs/f2fs/data.c
-+++ b/fs/f2fs/data.c
-@@ -2567,6 +2567,9 @@ static inline bool check_inplace_update_policy(struct inode *inode,
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- unsigned int policy = SM_I(sbi)->ipu_policy;
-
-+ if (policy & (0x1 << F2FS_IPU_HONOR_OPU_WRITE) &&
-+ is_inode_flag_set(inode, FI_OPU_WRITE))
-+ return false;
- if (policy & (0x1 << F2FS_IPU_FORCE))
- return true;
- if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi))
-@@ -2637,6 +2640,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
- if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
- return true;
-
-+ if (is_inode_flag_set(inode, FI_OPU_WRITE))
-+ return true;
-+
- if (fio) {
- if (page_private_gcing(fio->page))
- return true;
-@@ -3263,8 +3269,8 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
- f2fs_available_free_memory(sbi, DIRTY_DENTS))
- goto skip_write;
-
-- /* skip writing during file defragment */
-- if (is_inode_flag_set(inode, FI_DO_DEFRAG))
-+ /* skip writing in file defragment preparing stage */
-+ if (is_inode_flag_set(inode, FI_SKIP_WRITES))
- goto skip_write;
-
- trace_f2fs_writepages(mapping->host, wbc, DATA);
-@@ -3998,6 +4004,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
- filemap_invalidate_lock(inode->i_mapping);
-
- set_inode_flag(inode, FI_ALIGNED_WRITE);
-+ set_inode_flag(inode, FI_OPU_WRITE);
-
- for (; secidx < end_sec; secidx++) {
- down_write(&sbi->pin_sem);
-@@ -4006,7 +4013,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
- f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
- f2fs_unlock_op(sbi);
-
-- set_inode_flag(inode, FI_DO_DEFRAG);
-+ set_inode_flag(inode, FI_SKIP_WRITES);
-
- for (blkofs = 0; blkofs < blk_per_sec; blkofs++) {
- struct page *page;
-@@ -4023,7 +4030,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
- f2fs_put_page(page, 1);
- }
-
-- clear_inode_flag(inode, FI_DO_DEFRAG);
-+ clear_inode_flag(inode, FI_SKIP_WRITES);
-
- ret = filemap_fdatawrite(inode->i_mapping);
-
-@@ -4034,7 +4041,8 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
- }
-
- done:
-- clear_inode_flag(inode, FI_DO_DEFRAG);
-+ clear_inode_flag(inode, FI_SKIP_WRITES);
-+ clear_inode_flag(inode, FI_OPU_WRITE);
- clear_inode_flag(inode, FI_ALIGNED_WRITE);
-
- filemap_invalidate_unlock(inode->i_mapping);
-diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
-index fb1422a81d382..62390632db401 100644
---- a/fs/f2fs/f2fs.h
-+++ b/fs/f2fs/f2fs.h
-@@ -714,7 +714,8 @@ enum {
- FI_DROP_CACHE, /* drop dirty page cache */
- FI_DATA_EXIST, /* indicate data exists */
- FI_INLINE_DOTS, /* indicate inline dot dentries */
-- FI_DO_DEFRAG, /* indicate defragment is running */
-+ FI_SKIP_WRITES, /* should skip data page writeback */
-+ FI_OPU_WRITE, /* used for opu per file */
- FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
- FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
- FI_HOT_DATA, /* indicate file is hot */
-diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
-index be9536815e50d..0e6766d4eff57 100644
---- a/fs/f2fs/file.c
-+++ b/fs/f2fs/file.c
-@@ -2576,10 +2576,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
- bool fragmented = false;
- int err;
-
-- /* if in-place-update policy is enabled, don't waste time here */
-- if (f2fs_should_update_inplace(inode, NULL))
-- return -EINVAL;
--
- pg_start = range->start >> PAGE_SHIFT;
- pg_end = (range->start + range->len) >> PAGE_SHIFT;
-
-@@ -2587,6 +2583,13 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
-
- inode_lock(inode);
-
-+ /* if in-place-update policy is enabled, don't waste time here */
-+ set_inode_flag(inode, FI_OPU_WRITE);
-+ if (f2fs_should_update_inplace(inode, NULL)) {
-+ err = -EINVAL;
-+ goto out;
-+ }
-+
- /* writeback all dirty pages in the range */
- err = filemap_write_and_wait_range(inode->i_mapping, range->start,
- range->start + range->len - 1);
-@@ -2668,7 +2671,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
- goto check;
- }
-
-- set_inode_flag(inode, FI_DO_DEFRAG);
-+ set_inode_flag(inode, FI_SKIP_WRITES);
-
- idx = map.m_lblk;
- while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
-@@ -2694,15 +2697,16 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
- if (map.m_lblk < pg_end && cnt < blk_per_seg)
- goto do_map;
-
-- clear_inode_flag(inode, FI_DO_DEFRAG);
-+ clear_inode_flag(inode, FI_SKIP_WRITES);
-
- err = filemap_fdatawrite(inode->i_mapping);
- if (err)
- goto out;
- }
- clear_out:
-- clear_inode_flag(inode, FI_DO_DEFRAG);
-+ clear_inode_flag(inode, FI_SKIP_WRITES);
- out:
-+ clear_inode_flag(inode, FI_OPU_WRITE);
- inode_unlock(inode);
- if (!err)
- range->len = (u64)total << PAGE_SHIFT;
-diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
-index d1c0c8732c4fd..6d3a48407e1ba 100644
---- a/fs/f2fs/segment.h
-+++ b/fs/f2fs/segment.h
-@@ -667,7 +667,9 @@ static inline int utilization(struct f2fs_sb_info *sbi)
- * pages over min_fsync_blocks. (=default option)
- * F2FS_IPU_ASYNC - do IPU given by asynchronous write requests.
- * F2FS_IPU_NOCACHE - disable IPU bio cache.
-- * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode)
-+ * F2FS_IPU_HONOR_OPU_WRITE - use OPU write prior to IPU write if inode has
-+ * FI_OPU_WRITE flag.
-+ * F2FS_IPU_DISABLE - disable IPU. (=default option in LFS mode)
- */
- #define DEF_MIN_IPU_UTIL 70
- #define DEF_MIN_FSYNC_BLOCKS 8
-@@ -683,6 +685,7 @@ enum {
- F2FS_IPU_FSYNC,
- F2FS_IPU_ASYNC,
- F2FS_IPU_NOCACHE,
-+ F2FS_IPU_HONOR_OPU_WRITE,
- };
-
- static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
-diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
-index 144c35b2760f4..5ba244d01c6ea 100644
---- a/fs/f2fs/super.c
-+++ b/fs/f2fs/super.c
-@@ -3992,7 +3992,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
- F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
- if (f2fs_block_unit_discard(sbi))
- sm_i->dcc_info->discard_granularity = 1;
-- sm_i->ipu_policy = 1 << F2FS_IPU_FORCE;
-+ sm_i->ipu_policy = 1 << F2FS_IPU_FORCE |
-+ 1 << F2FS_IPU_HONOR_OPU_WRITE;
- }
-
- sbi->readdir_ra = 1;
---
-2.43.0
-
+++ /dev/null
-From bcfa36b10c3241ed299f21f0b186e97a9f064eed Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 29 Sep 2021 11:12:03 -0700
-Subject: f2fs: introduce fragment allocation mode mount option
-
-From: Daeho Jeong <daehojeong@google.com>
-
-[ Upstream commit 6691d940b0e09dd1564130e7a354d6deaf05d009 ]
-
-Added two options into "mode=" mount option to make it possible for
-developers to simulate filesystem fragmentation/after-GC situation
-itself. The developers use these modes to understand filesystem
-fragmentation/after-GC condition well, and eventually get some
-insights to handle them better.
-
-"fragment:segment": f2fs allocates a new segment in ramdom position.
- With this, we can simulate the after-GC condition.
-"fragment:block" : We can scatter block allocation with
- "max_fragment_chunk" and "max_fragment_hole" sysfs
- nodes. f2fs will allocate 1..<max_fragment_chunk>
- blocks in a chunk and make a hole in the length of
- 1..<max_fragment_hole> by turns in a newly allocated
- free segment. Plus, this mode implicitly enables
- "fragment:segment" option for more randomness.
-
-Reviewed-by: Chao Yu <chao@kernel.org>
-Signed-off-by: Daeho Jeong <daehojeong@google.com>
-Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-Stable-dep-of: f06c0f82e38b ("f2fs: fix to update user block counts in block_operations()")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- Documentation/ABI/testing/sysfs-fs-f2fs | 16 ++++++++++++++++
- Documentation/filesystems/f2fs.rst | 18 ++++++++++++++++++
- fs/f2fs/f2fs.h | 19 +++++++++++++++++--
- fs/f2fs/gc.c | 5 ++++-
- fs/f2fs/segment.c | 20 ++++++++++++++++++--
- fs/f2fs/segment.h | 1 +
- fs/f2fs/super.c | 10 ++++++++++
- fs/f2fs/sysfs.c | 20 ++++++++++++++++++++
- 8 files changed, 104 insertions(+), 5 deletions(-)
-
-diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
-index 48d41b6696270..91e2b549f8172 100644
---- a/Documentation/ABI/testing/sysfs-fs-f2fs
-+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
-@@ -513,3 +513,19 @@ Date: July 2021
- Contact: "Daeho Jeong" <daehojeong@google.com>
- Description: You can control the multiplier value of bdi device readahead window size
- between 2 (default) and 256 for POSIX_FADV_SEQUENTIAL advise option.
-+
-+What: /sys/fs/f2fs/<disk>/max_fragment_chunk
-+Date: August 2021
-+Contact: "Daeho Jeong" <daehojeong@google.com>
-+Description: With "mode=fragment:block" mount options, we can scatter block allocation.
-+ f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
-+ in the length of 1..<max_fragment_hole> by turns. This value can be set
-+ between 1..512 and the default value is 4.
-+
-+What: /sys/fs/f2fs/<disk>/max_fragment_hole
-+Date: August 2021
-+Contact: "Daeho Jeong" <daehojeong@google.com>
-+Description: With "mode=fragment:block" mount options, we can scatter block allocation.
-+ f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
-+ in the length of 1..<max_fragment_hole> by turns. This value can be set
-+ between 1..512 and the default value is 4.
-diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
-index 7fe50b0bccde9..6954c04753ad7 100644
---- a/Documentation/filesystems/f2fs.rst
-+++ b/Documentation/filesystems/f2fs.rst
-@@ -202,6 +202,24 @@ fault_type=%d Support configuring fault injection type, should be
- mode=%s Control block allocation mode which supports "adaptive"
- and "lfs". In "lfs" mode, there should be no random
- writes towards main area.
-+ "fragment:segment" and "fragment:block" are newly added here.
-+ These are developer options for experiments to simulate filesystem
-+ fragmentation/after-GC situation itself. The developers use these
-+ modes to understand filesystem fragmentation/after-GC condition well,
-+ and eventually get some insights to handle them better.
-+ In "fragment:segment", f2fs allocates a new segment in ramdom
-+ position. With this, we can simulate the after-GC condition.
-+ In "fragment:block", we can scatter block allocation with
-+ "max_fragment_chunk" and "max_fragment_hole" sysfs nodes.
-+ We added some randomness to both chunk and hole size to make
-+ it close to realistic IO pattern. So, in this mode, f2fs will allocate
-+ 1..<max_fragment_chunk> blocks in a chunk and make a hole in the
-+ length of 1..<max_fragment_hole> by turns. With this, the newly
-+ allocated blocks will be scattered throughout the whole partition.
-+ Note that "fragment:block" implicitly enables "fragment:segment"
-+ option for more randomness.
-+ Please, use these options for your experiments and we strongly
-+ recommend to re-format the filesystem after using these options.
- io_bits=%u Set the bit size of write IO requests. It should be set
- with "mode=lfs".
- usrquota Enable plain user disk quota accounting.
-diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
-index e49fca9daf2d3..b5f1099ab388f 100644
---- a/fs/f2fs/f2fs.h
-+++ b/fs/f2fs/f2fs.h
-@@ -1294,8 +1294,10 @@ enum {
- };
-
- enum {
-- FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
-- FS_MODE_LFS, /* use lfs allocation only */
-+ FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
-+ FS_MODE_LFS, /* use lfs allocation only */
-+ FS_MODE_FRAGMENT_SEG, /* segment fragmentation mode */
-+ FS_MODE_FRAGMENT_BLK, /* block fragmentation mode */
- };
-
- enum {
-@@ -1770,6 +1772,9 @@ struct f2fs_sb_info {
-
- unsigned long seq_file_ra_mul; /* multiplier for ra_pages of seq. files in fadvise */
-
-+ int max_fragment_chunk; /* max chunk size for block fragmentation mode */
-+ int max_fragment_hole; /* max hole size for block fragmentation mode */
-+
- #ifdef CONFIG_F2FS_FS_COMPRESSION
- struct kmem_cache *page_array_slab; /* page array entry */
- unsigned int page_array_slab_size; /* default page array slab size */
-@@ -3539,6 +3544,16 @@ unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
- unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
- unsigned int segno);
-
-+#define DEF_FRAGMENT_SIZE 4
-+#define MIN_FRAGMENT_SIZE 1
-+#define MAX_FRAGMENT_SIZE 512
-+
-+static inline bool f2fs_need_rand_seg(struct f2fs_sb_info *sbi)
-+{
-+ return F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG ||
-+ F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK;
-+}
-+
- /*
- * checkpoint.c
- */
-diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
-index 9a57754e6e0c1..4d4d7f0c8a71b 100644
---- a/fs/f2fs/gc.c
-+++ b/fs/f2fs/gc.c
-@@ -14,6 +14,7 @@
- #include <linux/delay.h>
- #include <linux/freezer.h>
- #include <linux/sched/signal.h>
-+#include <linux/random.h>
-
- #include "f2fs.h"
- #include "node.h"
-@@ -257,7 +258,9 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
- p->max_search = sbi->max_victim_search;
-
- /* let's select beginning hot/small space first in no_heap mode*/
-- if (test_opt(sbi, NOHEAP) &&
-+ if (f2fs_need_rand_seg(sbi))
-+ p->offset = prandom_u32() % (MAIN_SECS(sbi) * sbi->segs_per_sec);
-+ else if (test_opt(sbi, NOHEAP) &&
- (type == CURSEG_HOT_DATA || IS_NODESEG(type)))
- p->offset = 0;
- else
-diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
-index 1c69dc91c3292..b059b02fc179d 100644
---- a/fs/f2fs/segment.c
-+++ b/fs/f2fs/segment.c
-@@ -15,6 +15,7 @@
- #include <linux/timer.h>
- #include <linux/freezer.h>
- #include <linux/sched/signal.h>
-+#include <linux/random.h>
-
- #include "f2fs.h"
- #include "segment.h"
-@@ -2633,6 +2634,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
- unsigned short seg_type = curseg->seg_type;
-
- sanity_check_seg_type(sbi, seg_type);
-+ if (f2fs_need_rand_seg(sbi))
-+ return prandom_u32() % (MAIN_SECS(sbi) * sbi->segs_per_sec);
-
- /* if segs_per_sec is large than 1, we need to keep original policy. */
- if (__is_large_section(sbi))
-@@ -2684,6 +2687,9 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
- curseg->next_segno = segno;
- reset_curseg(sbi, type, 1);
- curseg->alloc_type = LFS;
-+ if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
-+ curseg->fragment_remained_chunk =
-+ prandom_u32() % sbi->max_fragment_chunk + 1;
- }
-
- static int __next_free_blkoff(struct f2fs_sb_info *sbi,
-@@ -2710,12 +2716,22 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,
- static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
- struct curseg_info *seg)
- {
-- if (seg->alloc_type == SSR)
-+ if (seg->alloc_type == SSR) {
- seg->next_blkoff =
- __next_free_blkoff(sbi, seg->segno,
- seg->next_blkoff + 1);
-- else
-+ } else {
- seg->next_blkoff++;
-+ if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) {
-+ /* To allocate block chunks in different sizes, use random number */
-+ if (--seg->fragment_remained_chunk <= 0) {
-+ seg->fragment_remained_chunk =
-+ prandom_u32() % sbi->max_fragment_chunk + 1;
-+ seg->next_blkoff +=
-+ prandom_u32() % sbi->max_fragment_hole + 1;
-+ }
-+ }
-+ }
- }
-
- bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
-diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
-index 1d16449089d02..d1c0c8732c4fd 100644
---- a/fs/f2fs/segment.h
-+++ b/fs/f2fs/segment.h
-@@ -321,6 +321,7 @@ struct curseg_info {
- unsigned short next_blkoff; /* next block offset to write */
- unsigned int zone; /* current zone number */
- unsigned int next_segno; /* preallocated segment */
-+ int fragment_remained_chunk; /* remained block size in a chunk for block fragmentation mode */
- bool inited; /* indicate inmem log is inited */
- };
-
-diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
-index 706d7adda3b22..339e44467b9cd 100644
---- a/fs/f2fs/super.c
-+++ b/fs/f2fs/super.c
-@@ -881,6 +881,10 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
- F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
- } else if (!strcmp(name, "lfs")) {
- F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
-+ } else if (!strcmp(name, "fragment:segment")) {
-+ F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG;
-+ } else if (!strcmp(name, "fragment:block")) {
-+ F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK;
- } else {
- kfree(name);
- return -EINVAL;
-@@ -1972,6 +1976,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
- seq_puts(seq, "adaptive");
- else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS)
- seq_puts(seq, "lfs");
-+ else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG)
-+ seq_puts(seq, "fragment:segment");
-+ else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
-+ seq_puts(seq, "fragment:block");
- seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
- if (test_opt(sbi, RESERVE_ROOT))
- seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
-@@ -3611,6 +3619,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
- sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
- sbi->migration_granularity = sbi->segs_per_sec;
- sbi->seq_file_ra_mul = MIN_RA_MUL;
-+ sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
-+ sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
-
- sbi->dir_level = DEF_DIR_LEVEL;
- sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
-diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
-index 63af1573ebcaa..c0e72bd44b135 100644
---- a/fs/f2fs/sysfs.c
-+++ b/fs/f2fs/sysfs.c
-@@ -553,6 +553,22 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
- return count;
- }
-
-+ if (!strcmp(a->attr.name, "max_fragment_chunk")) {
-+ if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE)
-+ sbi->max_fragment_chunk = t;
-+ else
-+ return -EINVAL;
-+ return count;
-+ }
-+
-+ if (!strcmp(a->attr.name, "max_fragment_hole")) {
-+ if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE)
-+ sbi->max_fragment_hole = t;
-+ else
-+ return -EINVAL;
-+ return count;
-+ }
-+
- *ui = (unsigned int)t;
-
- return count;
-@@ -783,6 +799,8 @@ F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, seq_file_ra_mul, seq_file_ra_mul);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_segment_mode, gc_segment_mode);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_reclaimed_segments, gc_reclaimed_segs);
-+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_chunk, max_fragment_chunk);
-+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_hole, max_fragment_hole);
-
- #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
- static struct attribute *f2fs_attrs[] = {
-@@ -861,6 +879,8 @@ static struct attribute *f2fs_attrs[] = {
- ATTR_LIST(seq_file_ra_mul),
- ATTR_LIST(gc_segment_mode),
- ATTR_LIST(gc_reclaimed_segments),
-+ ATTR_LIST(max_fragment_chunk),
-+ ATTR_LIST(max_fragment_hole),
- NULL,
- };
- ATTRIBUTE_GROUPS(f2fs);
---
-2.43.0
-
+++ /dev/null
-From 563606693cd1d2b34691aaff0e0f54f4afaecce7 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 29 Nov 2022 15:47:05 +0100
-Subject: i2c: qcom-geni: add desc struct to prepare support for I2C Master Hub
- variant
-
-From: Neil Armstrong <neil.armstrong@linaro.org>
-
-[ Upstream commit 14d02fbadb5dc1cdf66078ef8430dd1cd22bfd53 ]
-
-The I2C Master Hub is a stripped down version of the GENI Serial Engine
-QUP Wrapper Controller but only supporting I2C serial engines without
-DMA support.
-
-Those I2C serial engines variants have some requirements:
-- a separate "core" clock
-- doesn't support DMA, thus no memory interconnect path
-- fixed FIFO size not discoverable in the HW_PARAM_0 register
-
-Add a desc struct specifying all those requirements which will be used in
-a next change when adding the I2C Master Hub serial engine compatible.
-
-Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
-Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
-Signed-off-by: Wolfram Sang <wsa@kernel.org>
-Stable-dep-of: 9ba48db9f77c ("i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/i2c/busses/i2c-qcom-geni.c | 50 ++++++++++++++++++++++++++++--
- 1 file changed, 47 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
-index fc1dcc19f2a17..f811999e3aac9 100644
---- a/drivers/i2c/busses/i2c-qcom-geni.c
-+++ b/drivers/i2c/busses/i2c-qcom-geni.c
-@@ -88,6 +88,7 @@ struct geni_i2c_dev {
- int cur_wr;
- int cur_rd;
- spinlock_t lock;
-+ struct clk *core_clk;
- u32 clk_freq_out;
- const struct geni_i2c_clk_fld *clk_fld;
- int suspended;
-@@ -99,6 +100,13 @@ struct geni_i2c_dev {
- bool gpi_mode;
- };
-
-+struct geni_i2c_desc {
-+ bool has_core_clk;
-+ char *icc_ddr;
-+ bool no_dma_support;
-+ unsigned int tx_fifo_depth;
-+};
-+
- struct geni_i2c_err_log {
- int err;
- const char *msg;
-@@ -755,6 +763,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
- u32 proto, tx_depth, fifo_disable;
- int ret;
- struct device *dev = &pdev->dev;
-+ const struct geni_i2c_desc *desc = NULL;
-
- gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL);
- if (!gi2c)
-@@ -767,6 +776,14 @@ static int geni_i2c_probe(struct platform_device *pdev)
- if (IS_ERR(gi2c->se.base))
- return PTR_ERR(gi2c->se.base);
-
-+ desc = device_get_match_data(&pdev->dev);
-+
-+ if (desc && desc->has_core_clk) {
-+ gi2c->core_clk = devm_clk_get(dev, "core");
-+ if (IS_ERR(gi2c->core_clk))
-+ return PTR_ERR(gi2c->core_clk);
-+ }
-+
- gi2c->se.clk = devm_clk_get(dev, "se");
- if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev))
- return PTR_ERR(gi2c->se.clk);
-@@ -810,7 +827,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
- gi2c->adap.dev.of_node = dev->of_node;
- strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
-
-- ret = geni_icc_get(&gi2c->se, "qup-memory");
-+ ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory");
- if (ret)
- return ret;
- /*
-@@ -820,12 +837,17 @@ static int geni_i2c_probe(struct platform_device *pdev)
- */
- gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
- gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
-- gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
-+ if (!desc || desc->icc_ddr)
-+ gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
-
- ret = geni_icc_set_bw(&gi2c->se);
- if (ret)
- return ret;
-
-+ ret = clk_prepare_enable(gi2c->core_clk);
-+ if (ret)
-+ return ret;
-+
- ret = geni_se_resources_on(&gi2c->se);
- if (ret) {
- dev_err(dev, "Error turning on resources %d\n", ret);
-@@ -835,10 +857,15 @@ static int geni_i2c_probe(struct platform_device *pdev)
- if (proto != GENI_SE_I2C) {
- dev_err(dev, "Invalid proto %d\n", proto);
- geni_se_resources_off(&gi2c->se);
-+ clk_disable_unprepare(gi2c->core_clk);
- return -ENXIO;
- }
-
-- fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
-+ if (desc && desc->no_dma_support)
-+ fifo_disable = false;
-+ else
-+ fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
-+
- if (fifo_disable) {
- /* FIFO is disabled, so we can only use GPI DMA */
- gi2c->gpi_mode = true;
-@@ -852,6 +879,16 @@ static int geni_i2c_probe(struct platform_device *pdev)
- } else {
- gi2c->gpi_mode = false;
- tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
-+
-+ /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
-+ if (!tx_depth && desc)
-+ tx_depth = desc->tx_fifo_depth;
-+
-+ if (!tx_depth) {
-+ dev_err(dev, "Invalid TX FIFO depth\n");
-+ return -EINVAL;
-+ }
-+
- gi2c->tx_wm = tx_depth - 1;
- geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
- geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
-@@ -860,6 +897,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
- dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
- }
-
-+ clk_disable_unprepare(gi2c->core_clk);
- ret = geni_se_resources_off(&gi2c->se);
- if (ret) {
- dev_err(dev, "Error turning off resources %d\n", ret);
-@@ -925,6 +963,8 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
- gi2c->suspended = 1;
- }
-
-+ clk_disable_unprepare(gi2c->core_clk);
-+
- return geni_icc_disable(&gi2c->se);
- }
-
-@@ -937,6 +977,10 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
- if (ret)
- return ret;
-
-+ ret = clk_prepare_enable(gi2c->core_clk);
-+ if (ret)
-+ return ret;
-+
- ret = geni_se_resources_on(&gi2c->se);
- if (ret)
- return ret;
---
-2.43.0
-
+++ /dev/null
-From b9fab584c4f59346c3397e566b2172bf35e5d282 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sat, 3 Aug 2024 14:10:41 +0800
-Subject: i2c: qcom-geni: Add missing clk_disable_unprepare in
- geni_i2c_runtime_resume
-
-From: Gaosheng Cui <cuigaosheng1@huawei.com>
-
-[ Upstream commit b93d16bee557302d4e588375ececd833cc048acc ]
-
-Add the missing clk_disable_unprepare() before return in
-geni_i2c_runtime_resume().
-
-Fixes: 14d02fbadb5d ("i2c: qcom-geni: add desc struct to prepare support for I2C Master Hub variant")
-Signed-off-by: Gaosheng Cui <cuigaosheng1@huawei.com>
-Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
-Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
-Stable-dep-of: 9ba48db9f77c ("i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/i2c/busses/i2c-qcom-geni.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
-index f811999e3aac9..27a7cca3918c6 100644
---- a/drivers/i2c/busses/i2c-qcom-geni.c
-+++ b/drivers/i2c/busses/i2c-qcom-geni.c
-@@ -982,8 +982,10 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
- return ret;
-
- ret = geni_se_resources_on(&gi2c->se);
-- if (ret)
-+ if (ret) {
-+ clk_disable_unprepare(gi2c->core_clk);
- return ret;
-+ }
-
- enable_irq(gi2c->irq);
- gi2c->suspended = 0;
---
-2.43.0
-
+++ /dev/null
-From f9edc08d44840561dfcf88791c40eab30d6a9598 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 6 Aug 2024 20:53:31 +0800
-Subject: i2c: qcom-geni: Add missing geni_icc_disable in
- geni_i2c_runtime_resume
-
-From: Gaosheng Cui <cuigaosheng1@huawei.com>
-
-[ Upstream commit 9ba48db9f77ce0001dbb882476fa46e092feb695 ]
-
-Add the missing geni_icc_disable() before return in
-geni_i2c_runtime_resume().
-
-Fixes: bf225ed357c6 ("i2c: i2c-qcom-geni: Add interconnect support")
-Signed-off-by: Gaosheng Cui <cuigaosheng1@huawei.com>
-Reviewed-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
-Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/i2c/busses/i2c-qcom-geni.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
-index 27a7cca3918c6..8eb64b09cf58e 100644
---- a/drivers/i2c/busses/i2c-qcom-geni.c
-+++ b/drivers/i2c/busses/i2c-qcom-geni.c
-@@ -984,6 +984,7 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
- ret = geni_se_resources_on(&gi2c->se);
- if (ret) {
- clk_disable_unprepare(gi2c->core_clk);
-+ geni_icc_disable(&gi2c->se);
- return ret;
- }
-
---
-2.43.0
-
+++ /dev/null
-From 7d1839cf943c210a5741981a805f402cc4ec3668 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 21 Feb 2022 15:57:16 +0530
-Subject: i2c: qcom-geni: Add support for GPI DMA
-
-From: Vinod Koul <vkoul@kernel.org>
-
-[ Upstream commit d8703554f4dea9775417525b22b3d65ed1c6b16e ]
-
-QUP Serial engines supports data transfers thru FIFO mode, SE DMA mode
-and lastly GPI DMA mode. Former two are already supported and this adds
-supports for the last mode.
-
-In GPI DMA mode, the firmware is issued commands by driver to perform
-DMA and setup the serial port.
-
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
-Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
-Signed-off-by: Wolfram Sang <wsa@kernel.org>
-Stable-dep-of: 9ba48db9f77c ("i2c: qcom-geni: Add missing geni_icc_disable in geni_i2c_runtime_resume")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/i2c/busses/i2c-qcom-geni.c | 308 ++++++++++++++++++++++++++---
- 1 file changed, 280 insertions(+), 28 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
-index 6d635a7c104ce..fc1dcc19f2a17 100644
---- a/drivers/i2c/busses/i2c-qcom-geni.c
-+++ b/drivers/i2c/busses/i2c-qcom-geni.c
-@@ -3,7 +3,9 @@
-
- #include <linux/acpi.h>
- #include <linux/clk.h>
-+#include <linux/dmaengine.h>
- #include <linux/dma-mapping.h>
-+#include <linux/dma/qcom-gpi-dma.h>
- #include <linux/err.h>
- #include <linux/i2c.h>
- #include <linux/interrupt.h>
-@@ -48,6 +50,9 @@
- #define LOW_COUNTER_SHFT 10
- #define CYCLE_COUNTER_MSK GENMASK(9, 0)
-
-+#define I2C_PACK_TX BIT(0)
-+#define I2C_PACK_RX BIT(1)
-+
- enum geni_i2c_err_code {
- GP_IRQ0,
- NACK,
-@@ -89,6 +94,9 @@ struct geni_i2c_dev {
- void *dma_buf;
- size_t xfer_len;
- dma_addr_t dma_addr;
-+ struct dma_chan *tx_c;
-+ struct dma_chan *rx_c;
-+ bool gpi_mode;
- };
-
- struct geni_i2c_err_log {
-@@ -456,12 +464,207 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
- return gi2c->err;
- }
-
-+static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
-+{
-+ struct geni_i2c_dev *gi2c = cb;
-+
-+ if (result->result != DMA_TRANS_NOERROR) {
-+ dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
-+ gi2c->err = -EIO;
-+ } else if (result->residue) {
-+ dev_dbg(gi2c->se.dev, "DMA xfer has pending: %d\n", result->residue);
-+ }
-+
-+ complete(&gi2c->done);
-+}
-+
-+static void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
-+ void *tx_buf, dma_addr_t tx_addr,
-+ void *rx_buf, dma_addr_t rx_addr)
-+{
-+ if (tx_buf) {
-+ dma_unmap_single(gi2c->se.dev->parent, tx_addr, msg->len, DMA_TO_DEVICE);
-+ i2c_put_dma_safe_msg_buf(tx_buf, msg, false);
-+ }
-+
-+ if (rx_buf) {
-+ dma_unmap_single(gi2c->se.dev->parent, rx_addr, msg->len, DMA_FROM_DEVICE);
-+ i2c_put_dma_safe_msg_buf(rx_buf, msg, false);
-+ }
-+}
-+
-+static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
-+ struct dma_slave_config *config, dma_addr_t *dma_addr_p,
-+ void **buf, unsigned int op, struct dma_chan *dma_chan)
-+{
-+ struct gpi_i2c_config *peripheral;
-+ unsigned int flags;
-+ void *dma_buf;
-+ dma_addr_t addr;
-+ enum dma_data_direction map_dirn;
-+ enum dma_transfer_direction dma_dirn;
-+ struct dma_async_tx_descriptor *desc;
-+ int ret;
-+
-+ peripheral = config->peripheral_config;
-+
-+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 1);
-+ if (!dma_buf)
-+ return -ENOMEM;
-+
-+ if (op == I2C_WRITE)
-+ map_dirn = DMA_TO_DEVICE;
-+ else
-+ map_dirn = DMA_FROM_DEVICE;
-+
-+ addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn);
-+ if (dma_mapping_error(gi2c->se.dev->parent, addr)) {
-+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
-+ return -ENOMEM;
-+ }
-+
-+ /* set the length as message for rx txn */
-+ peripheral->rx_len = msg->len;
-+ peripheral->op = op;
-+
-+ ret = dmaengine_slave_config(dma_chan, config);
-+ if (ret) {
-+ dev_err(gi2c->se.dev, "dma config error: %d for op:%d\n", ret, op);
-+ goto err_config;
-+ }
-+
-+ peripheral->set_config = 0;
-+ peripheral->multi_msg = true;
-+ flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
-+
-+ if (op == I2C_WRITE)
-+ dma_dirn = DMA_MEM_TO_DEV;
-+ else
-+ dma_dirn = DMA_DEV_TO_MEM;
-+
-+ desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags);
-+ if (!desc) {
-+ dev_err(gi2c->se.dev, "prep_slave_sg failed\n");
-+ ret = -EIO;
-+ goto err_config;
-+ }
-+
-+ desc->callback_result = i2c_gpi_cb_result;
-+ desc->callback_param = gi2c;
-+
-+ dmaengine_submit(desc);
-+ *dma_addr_p = addr;
-+
-+ return 0;
-+
-+err_config:
-+ dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn);
-+ i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
-+ return ret;
-+}
-+
-+static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], int num)
-+{
-+ struct dma_slave_config config = {};
-+ struct gpi_i2c_config peripheral = {};
-+ int i, ret = 0, timeout;
-+ dma_addr_t tx_addr, rx_addr;
-+ void *tx_buf = NULL, *rx_buf = NULL;
-+ const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
-+
-+ config.peripheral_config = &peripheral;
-+ config.peripheral_size = sizeof(peripheral);
-+
-+ peripheral.pack_enable = I2C_PACK_TX | I2C_PACK_RX;
-+ peripheral.cycle_count = itr->t_cycle_cnt;
-+ peripheral.high_count = itr->t_high_cnt;
-+ peripheral.low_count = itr->t_low_cnt;
-+ peripheral.clk_div = itr->clk_div;
-+ peripheral.set_config = 1;
-+ peripheral.multi_msg = false;
-+
-+ for (i = 0; i < num; i++) {
-+ gi2c->cur = &msgs[i];
-+ gi2c->err = 0;
-+ dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
-+
-+ peripheral.stretch = 0;
-+ if (i < num - 1)
-+ peripheral.stretch = 1;
-+
-+ peripheral.addr = msgs[i].addr;
-+
-+ if (msgs[i].flags & I2C_M_RD) {
-+ ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
-+ &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c);
-+ if (ret)
-+ goto err;
-+ }
-+
-+ ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
-+ &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
-+ if (ret)
-+ goto err;
-+
-+ if (msgs[i].flags & I2C_M_RD)
-+ dma_async_issue_pending(gi2c->rx_c);
-+ dma_async_issue_pending(gi2c->tx_c);
-+
-+ timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
-+ if (!timeout) {
-+ dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n",
-+ gi2c->cur->flags, gi2c->cur->addr);
-+ gi2c->err = -ETIMEDOUT;
-+ goto err;
-+ }
-+
-+ if (gi2c->err) {
-+ ret = gi2c->err;
-+ goto err;
-+ }
-+
-+ geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
-+ }
-+
-+ return num;
-+
-+err:
-+ dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret);
-+ dmaengine_terminate_sync(gi2c->rx_c);
-+ dmaengine_terminate_sync(gi2c->tx_c);
-+ geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
-+ return ret;
-+}
-+
-+static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
-+ struct i2c_msg msgs[], int num)
-+{
-+ int i, ret = 0;
-+
-+ for (i = 0; i < num; i++) {
-+ u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
-+
-+ m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
-+
-+ gi2c->cur = &msgs[i];
-+ if (msgs[i].flags & I2C_M_RD)
-+ ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
-+ else
-+ ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param);
-+
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return num;
-+}
-+
- static int geni_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg msgs[],
- int num)
- {
- struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
-- int i, ret;
-+ int ret;
-
- gi2c->err = 0;
- reinit_completion(&gi2c->done);
-@@ -475,28 +678,17 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
- }
-
- qcom_geni_i2c_conf(gi2c);
-- for (i = 0; i < num; i++) {
-- u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
--
-- m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
--
-- gi2c->cur = &msgs[i];
-- if (msgs[i].flags & I2C_M_RD)
-- ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
-- else
-- ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param);
-
-- if (ret)
-- break;
-- }
-- if (ret == 0)
-- ret = num;
-+ if (gi2c->gpi_mode)
-+ ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
-+ else
-+ ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
-
- pm_runtime_mark_last_busy(gi2c->se.dev);
- pm_runtime_put_autosuspend(gi2c->se.dev);
- gi2c->cur = NULL;
- gi2c->err = 0;
-- return ret;
-+ return num;
- }
-
- static u32 geni_i2c_func(struct i2c_adapter *adap)
-@@ -517,11 +709,50 @@ static const struct acpi_device_id geni_i2c_acpi_match[] = {
- MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
- #endif
-
-+static void release_gpi_dma(struct geni_i2c_dev *gi2c)
-+{
-+ if (gi2c->rx_c)
-+ dma_release_channel(gi2c->rx_c);
-+
-+ if (gi2c->tx_c)
-+ dma_release_channel(gi2c->tx_c);
-+}
-+
-+static int setup_gpi_dma(struct geni_i2c_dev *gi2c)
-+{
-+ int ret;
-+
-+ geni_se_select_mode(&gi2c->se, GENI_GPI_DMA);
-+ gi2c->tx_c = dma_request_chan(gi2c->se.dev, "tx");
-+ if (IS_ERR(gi2c->tx_c)) {
-+ ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->tx_c),
-+ "Failed to get tx DMA ch\n");
-+ if (ret < 0)
-+ goto err_tx;
-+ }
-+
-+ gi2c->rx_c = dma_request_chan(gi2c->se.dev, "rx");
-+ if (IS_ERR(gi2c->rx_c)) {
-+ ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->rx_c),
-+ "Failed to get rx DMA ch\n");
-+ if (ret < 0)
-+ goto err_rx;
-+ }
-+
-+ dev_dbg(gi2c->se.dev, "Grabbed GPI dma channels\n");
-+ return 0;
-+
-+err_rx:
-+ dma_release_channel(gi2c->tx_c);
-+err_tx:
-+ return ret;
-+}
-+
- static int geni_i2c_probe(struct platform_device *pdev)
- {
- struct geni_i2c_dev *gi2c;
- struct resource *res;
-- u32 proto, tx_depth;
-+ u32 proto, tx_depth, fifo_disable;
- int ret;
- struct device *dev = &pdev->dev;
-
-@@ -601,27 +832,43 @@ static int geni_i2c_probe(struct platform_device *pdev)
- return ret;
- }
- proto = geni_se_read_proto(&gi2c->se);
-- tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
- if (proto != GENI_SE_I2C) {
- dev_err(dev, "Invalid proto %d\n", proto);
- geni_se_resources_off(&gi2c->se);
- return -ENXIO;
- }
-- gi2c->tx_wm = tx_depth - 1;
-- geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
-- geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW,
-- true, true, true);
-+
-+ fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
-+ if (fifo_disable) {
-+ /* FIFO is disabled, so we can only use GPI DMA */
-+ gi2c->gpi_mode = true;
-+ ret = setup_gpi_dma(gi2c);
-+ if (ret) {
-+ dev_err(dev, "Failed to setup GPI DMA mode:%d ret\n", ret);
-+ return ret;
-+ }
-+
-+ dev_dbg(dev, "Using GPI DMA mode for I2C\n");
-+ } else {
-+ gi2c->gpi_mode = false;
-+ tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
-+ gi2c->tx_wm = tx_depth - 1;
-+ geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
-+ geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
-+ PACKING_BYTES_PW, true, true, true);
-+
-+ dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
-+ }
-+
- ret = geni_se_resources_off(&gi2c->se);
- if (ret) {
- dev_err(dev, "Error turning off resources %d\n", ret);
-- return ret;
-+ goto err_dma;
- }
-
- ret = geni_icc_disable(&gi2c->se);
- if (ret)
-- return ret;
--
-- dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
-+ goto err_dma;
-
- gi2c->suspended = 1;
- pm_runtime_set_suspended(gi2c->se.dev);
-@@ -633,12 +880,16 @@ static int geni_i2c_probe(struct platform_device *pdev)
- if (ret) {
- dev_err(dev, "Error adding i2c adapter %d\n", ret);
- pm_runtime_disable(gi2c->se.dev);
-- return ret;
-+ goto err_dma;
- }
-
- dev_dbg(dev, "Geni-I2C adaptor successfully added\n");
-
- return 0;
-+
-+err_dma:
-+ release_gpi_dma(gi2c);
-+ return ret;
- }
-
- static int geni_i2c_remove(struct platform_device *pdev)
-@@ -646,6 +897,7 @@ static int geni_i2c_remove(struct platform_device *pdev)
- struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
-
- i2c_del_adapter(&gi2c->adap);
-+ release_gpi_dma(gi2c);
- pm_runtime_disable(gi2c->se.dev);
- return 0;
- }
---
-2.43.0
-
+f2fs-fix-return-value-of-f2fs_convert_inline_inode.patch
+f2fs-fix-to-don-t-dirty-inode-for-readonly-filesystem.patch
edac-i10nm-make-skx_common.o-a-separate-module.patch
platform-chrome-cros_ec_debugfs-fix-wrong-ec-message.patch
block-refactor-to-use-helper.patch
dev-parport-fix-the-array-out-of-bounds-risk.patch
fs-ntfs3-update-log-page_-mask-bits-if-log-page_size-changed.patch
scsi-qla2xxx-return-enobufs-if-sg_cnt-is-more-than-one-for-els-cmds.patch
-f2fs-fix-to-don-t-dirty-inode-for-readonly-filesystem.patch
-f2fs-fix-return-value-of-f2fs_convert_inline_inode.patch
clk-davinci-da8xx-cfgchip-initialize-clk_init_data-before-use.patch
ubi-eba-properly-rollback-inside-self_check_eba.patch
decompress_bunzip2-fix-rare-decompression-failure.patch
phy-cadence-torrent-check-return-value-on-register-r.patch
um-time-travel-fix-time-travel-start-option.patch
um-time-travel-fix-signal-blocking-race-hang.patch
-f2fs-fix-start-segno-of-large-section.patch
-f2fs-introduce-fragment-allocation-mode-mount-option.patch
-f2fs-add-gc_urgent_high_remaining-sysfs-node.patch
-f2fs-add-a-way-to-limit-roll-forward-recovery-time.patch
-f2fs-fix-to-update-user-block-counts-in-block_operat.patch
libbpf-fix-no-args-func-prototype-btf-dumping-syntax.patch
dma-fix-call-order-in-dmam_free_coherent.patch
bpf-events-use-prog-to-emit-ksymbol-event-for-main-p.patch
nvme-pci-add-missing-condition-check-for-existence-o.patch
fs-don-t-allow-non-init-s_user_ns-for-filesystems-wi.patch
powerpc-configs-update-defconfig-with-now-user-visible-config_fsl_ifc.patch
-f2fs-fix-wrong-continue-condition-in-gc.patch
arm64-dts-qcom-msm8996-move-clock-cells-to-qmp-phy-c.patch
arm64-dts-qcom-msm8998-drop-usb-phy-clock-index.patch
arm64-dts-qcom-msm8998-switch-usb-qmp-phy-to-new-sty.patch
leds-trigger-store-brightness-set-by-led_trigger_eve.patch
leds-trigger-call-synchronize_rcu-before-calling-tri.patch
leds-triggers-flush-pending-brightness-before-activa.patch
-f2fs-introduce-f2fs_ipu_honor_opu_write-ipu-policy.patch
-f2fs-fix-to-avoid-use-ssr-allocate-when-do-defragmen.patch
-f2fs-assign-curseg_all_data_atgc-if-blkaddr-is-valid.patch
irqdomain-fixed-unbalanced-fwnode-get-and-put.patch
genirq-allow-the-pm-device-to-originate-from-irq-dom.patch
irqchip-imx-irqsteer-constify-irq_chip-struct.patch
i2c-smbus-send-alert-notifications-to-all-devices-if.patch
bpf-kprobe-remove-unused-declaring-of-bpf_kprobe_ove.patch
kprobes-fix-to-check-symbol-prefixes-correctly.patch
-i2c-qcom-geni-add-support-for-gpi-dma.patch
-i2c-qcom-geni-add-desc-struct-to-prepare-support-for.patch
-i2c-qcom-geni-add-missing-clk_disable_unprepare-in-g.patch
-i2c-qcom-geni-add-missing-geni_icc_disable-in-geni_i.patch
spi-spi-fsl-lpspi-fix-scldiv-calculation.patch
alsa-usb-audio-re-add-scratchamp-quirk-entries.patch
asoc-meson-axg-fifo-fix-irq-scheduling-issue-with-pr.patch