public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore
@ 2026-01-04  2:07 Chao Yu
  2026-01-04  2:07 ` [PATCH 02/14] f2fs: sysfs: introduce max_lock_elapsed_time Chao Yu
                   ` (14 more replies)
  0 siblings, 15 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

This patch adds lock elapsed time trace facility for f2fs rwsemphore.

If total elapsed time of critical region covered by lock exceeds a
threshold, it will print tracepoint to dump information of lock related
context, including:
- thread information
- CPU/IO priority
- lock information
- elapsed time
 - total time
 - running time (depend on CONFIG_64BIT)
 - runnable time (depend on CONFIG_SCHED_INFO and CONFIG_SCHEDSTATS)
 - io sleep time (depend on CONFIG_TASK_DELAY_ACCT and
		  /proc/sys/kernel/task_delayacct)
 - other time    (by default other time will account nonio sleep time,
                  but, if above kconfig is not defined, other time will
                  include runnable time and/or io sleep time as wll)

output:
    f2fs_lock_elapsed_time: dev = (254,52), comm: sh, pid: 13855, prio: 120, ioprio_class: 2, ioprio_data: 4, lock_name: cp_rwsem, lock_type: rlock, total: 1000, running: 993, runnable: 2, io_sleep: 0, other: 5

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/checkpoint.c        | 106 ++++++++++++++++++++++++++++++++++++
 fs/f2fs/f2fs.h              |  51 +++++++++++++++--
 include/trace/events/f2fs.h |  68 +++++++++++++++++++++++
 3 files changed, 221 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 300664269eb6..bc6058a3122b 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -14,6 +14,9 @@
 #include <linux/pagevec.h>
 #include <linux/swap.h>
 #include <linux/kthread.h>
+#include <linux/delayacct.h>
+#include <linux/ioprio.h>
+#include <linux/math64.h>
 
 #include "f2fs.h"
 #include "node.h"
@@ -21,6 +24,109 @@
 #include "iostat.h"
 #include <trace/events/f2fs.h>
 
+static inline void get_lock_elapsed_time(struct f2fs_time_stat *ts)
+{
+	ts->total_time = ktime_get();
+#ifdef CONFIG_64BIT
+	ts->running_time = current->se.sum_exec_runtime;
+#endif
+#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
+	ts->runnable_time = current->sched_info.run_delay;
+#endif
+#ifdef CONFIG_TASK_DELAY_ACCT
+	if (current->delays)
+		ts->io_sleep_time = current->delays->blkio_delay;
+#endif
+}
+
+static inline void trace_lock_elapsed_time_start(struct f2fs_rwsem *sem,
+						struct f2fs_lock_context *lc)
+{
+	lc->lock_trace = trace_f2fs_lock_elapsed_time_enabled();
+	if (!lc->lock_trace)
+		return;
+
+	get_lock_elapsed_time(&lc->ts);
+}
+
+static inline void trace_lock_elapsed_time_end(struct f2fs_rwsem *sem,
+				struct f2fs_lock_context *lc, bool is_write)
+{
+	struct f2fs_time_stat tts;
+	unsigned long long total_time;
+	unsigned long long running_time = 0;
+	unsigned long long runnable_time = 0;
+	unsigned long long io_sleep_time = 0;
+	unsigned long long other_time = 0;
+	unsigned npm = NSEC_PER_MSEC;
+
+	if (!lc->lock_trace)
+		return;
+
+	get_lock_elapsed_time(&tts);
+
+	total_time = div_u64(tts.total_time - lc->ts.total_time, npm);
+	if (total_time <= MAX_LOCK_ELAPSED_TIME)
+		return;
+
+#ifdef CONFIG_64BIT
+	running_time = div_u64(tts.running_time - lc->ts.running_time, npm);
+#endif
+#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
+	runnable_time = div_u64(tts.runnable_time - lc->ts.runnable_time, npm);
+#endif
+#ifdef CONFIG_TASK_DELAY_ACCT
+	io_sleep_time = div_u64(tts.io_sleep_time - lc->ts.io_sleep_time, npm);
+#endif
+	if (total_time > running_time + io_sleep_time + runnable_time)
+		other_time = total_time - running_time -
+				io_sleep_time - runnable_time;
+
+	trace_f2fs_lock_elapsed_time(sem->sbi, sem->name, is_write, current,
+			get_current_ioprio(), total_time, running_time,
+			runnable_time, io_sleep_time, other_time);
+}
+
+void f2fs_down_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	f2fs_down_read(sem);
+	trace_lock_elapsed_time_start(sem, lc);
+}
+
+int f2fs_down_read_trylock_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	if (!f2fs_down_read_trylock(sem))
+		return 0;
+	trace_lock_elapsed_time_start(sem, lc);
+	return 1;
+}
+
+void f2fs_up_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	f2fs_up_read(sem);
+	trace_lock_elapsed_time_end(sem, lc, false);
+}
+
+void f2fs_down_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	f2fs_down_write(sem);
+	trace_lock_elapsed_time_start(sem, lc);
+}
+
+int f2fs_down_write_trylock_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	if (!f2fs_down_write_trylock(sem))
+		return 0;
+	trace_lock_elapsed_time_start(sem, lc);
+	return 1;
+}
+
+void f2fs_up_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
+{
+	f2fs_up_write(sem);
+	trace_lock_elapsed_time_end(sem, lc, true);
+}
+
 #define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 3))
 
 static struct kmem_cache *ino_entry_slab;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c3e1611fce18..7e22315dbedd 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -173,6 +173,10 @@ enum device_allocation_policy {
 	ALLOCATE_FORWARD_FROM_HINT,
 };
 
+enum f2fs_lock_name {
+	LOCK_NAME_NONE,
+};
+
 /*
  * An implementation of an rwsem that is explicitly unfair to readers. This
  * prevents priority inversion when a low-priority reader acquires the read lock
@@ -181,6 +185,8 @@ enum device_allocation_policy {
  */
 
 struct f2fs_rwsem {
+	struct f2fs_sb_info *sbi;
+	enum f2fs_lock_name name;
         struct rw_semaphore internal_rwsem;
 #ifdef CONFIG_F2FS_UNFAIR_RWSEM
         wait_queue_head_t read_waiters;
@@ -1409,6 +1415,24 @@ struct f2fs_gc_control {
 	unsigned int nr_free_secs;	/* # of free sections to do GC */
 };
 
+struct f2fs_time_stat {
+	unsigned long long total_time;		/* total wall clock time */
+#ifdef CONFIG_64BIT
+	unsigned long long running_time;	/* running time */
+#endif
+#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
+	unsigned long long runnable_time;	/* runnable(including preempted) time */
+#endif
+#ifdef CONFIG_TASK_DELAY_ACCT
+	unsigned long long io_sleep_time;	/* IO sleep time */
+#endif
+};
+
+struct f2fs_lock_context {
+	struct f2fs_time_stat ts;
+	bool lock_trace;
+};
+
 /*
  * For s_flag in struct f2fs_sb_info
  * Modification on enum should be synchronized with s_flag array
@@ -1525,6 +1549,9 @@ enum f2fs_lookup_mode {
 	LOOKUP_AUTO,
 };
 
+/* a threshold of maximum elapsed time in critical region to print tracepoint */
+#define MAX_LOCK_ELAPSED_TIME		500
+
 static inline int f2fs_test_bit(unsigned int nr, char *addr);
 static inline void f2fs_set_bit(unsigned int nr, char *addr);
 static inline void f2fs_clear_bit(unsigned int nr, char *addr);
@@ -2263,16 +2290,22 @@ static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
 	spin_unlock_irqrestore(&sbi->cp_lock, flags);
 }
 
-#define init_f2fs_rwsem(sem)					\
+#define init_f2fs_rwsem(sem)	__init_f2fs_rwsem(sem, NULL, LOCK_NAME_NONE)
+#define init_f2fs_rwsem_trace	__init_f2fs_rwsem
+
+#define __init_f2fs_rwsem(sem, sbi, name)			\
 do {								\
 	static struct lock_class_key __key;			\
 								\
-	__init_f2fs_rwsem((sem), #sem, &__key);			\
+	do_init_f2fs_rwsem((sem), #sem, &__key, sbi, name);	\
 } while (0)
 
-static inline void __init_f2fs_rwsem(struct f2fs_rwsem *sem,
-		const char *sem_name, struct lock_class_key *key)
+static inline void do_init_f2fs_rwsem(struct f2fs_rwsem *sem,
+		const char *sem_name, struct lock_class_key *key,
+		struct f2fs_sb_info *sbi, enum f2fs_lock_name name)
 {
+	sem->sbi = sbi;
+	sem->name = name;
 	__init_rwsem(&sem->internal_rwsem, sem_name, key);
 #ifdef CONFIG_F2FS_UNFAIR_RWSEM
 	init_waitqueue_head(&sem->read_waiters);
@@ -2341,6 +2374,16 @@ static inline void f2fs_up_write(struct f2fs_rwsem *sem)
 #endif
 }
 
+void f2fs_down_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
+int f2fs_down_read_trylock_trace(struct f2fs_rwsem *sem,
+						struct f2fs_lock_context *lc);
+void f2fs_up_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
+void f2fs_down_write_trace(struct f2fs_rwsem *sem,
+						struct f2fs_lock_context *lc);
+int f2fs_down_write_trylock_trace(struct f2fs_rwsem *sem,
+						struct f2fs_lock_context *lc);
+void f2fs_up_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
+
 static inline void disable_nat_bits(struct f2fs_sb_info *sbi, bool lock)
 {
 	unsigned long flags;
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 635dcabcf1c7..9a852a16df9c 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -184,6 +184,10 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 		{ CP_PHASE_FINISH_BLOCK_OPS,	"finish block_ops" },			\
 		{ CP_PHASE_FINISH_CHECKPOINT,	"finish checkpoint" })
 
+#define show_lock_name(lock)						\
+	__print_symbolic(lock,						\
+		{ LOCK_NAME_NONE,		"none" })
+
 struct f2fs_sb_info;
 struct f2fs_io_info;
 struct extent_info;
@@ -2452,6 +2456,70 @@ DEFINE_EVENT(f2fs__rw_end, f2fs_datawrite_end,
 	TP_ARGS(inode, offset, bytes)
 );
 
+TRACE_EVENT(f2fs_lock_elapsed_time,
+
+	TP_PROTO(struct f2fs_sb_info *sbi, enum f2fs_lock_name lock_name,
+		bool is_write, struct task_struct *p, int ioprio,
+		unsigned long long total_time,
+		unsigned long long running_time,
+		unsigned long long runnable_time,
+		unsigned long long io_sleep_time,
+		unsigned long long other_time),
+
+	TP_ARGS(sbi, lock_name, is_write, p, ioprio, total_time, running_time,
+		runnable_time, io_sleep_time, other_time),
+
+	TP_STRUCT__entry(
+		__field(dev_t, dev)
+		__array(char, comm, TASK_COMM_LEN)
+		__field(pid_t, pid)
+		__field(int, prio)
+		__field(int, ioprio_class)
+		__field(int, ioprio_data)
+		__field(unsigned int, lock_name)
+		__field(bool, is_write)
+		__field(unsigned long long, total_time)
+		__field(unsigned long long, running_time)
+		__field(unsigned long long, runnable_time)
+		__field(unsigned long long, io_sleep_time)
+		__field(unsigned long long, other_time)
+	),
+
+	TP_fast_assign(
+		__entry->dev		= sbi->sb->s_dev;
+		memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+		__entry->pid		= p->pid;
+		__entry->prio		= p->prio;
+		__entry->ioprio_class	= IOPRIO_PRIO_CLASS(ioprio);
+		__entry->ioprio_data	= IOPRIO_PRIO_DATA(ioprio);
+		__entry->lock_name	= lock_name;
+		__entry->is_write	= is_write;
+		__entry->total_time	= total_time;
+		__entry->running_time	= running_time;
+		__entry->runnable_time	= runnable_time;
+		__entry->io_sleep_time	= io_sleep_time;
+		__entry->other_time	= other_time;
+	),
+
+	TP_printk("dev = (%d,%d), comm: %s, pid: %d, prio: %d, "
+		"ioprio_class: %d, ioprio_data: %d, lock_name: %s, "
+		"lock_type: %s, total: %llu, running: %llu, "
+		"runnable: %llu, io_sleep: %llu, other: %llu",
+		show_dev(__entry->dev),
+		__entry->comm,
+		__entry->pid,
+		__entry->prio,
+		__entry->ioprio_class,
+		__entry->ioprio_data,
+		show_lock_name(__entry->lock_name),
+		__entry->is_write ? "wlock" : "rlock",
+		__entry->total_time,
+		__entry->running_time,
+		__entry->runnable_time,
+		__entry->io_sleep_time,
+		__entry->other_time)
+);
+
 #endif /* _TRACE_F2FS_H */
 
  /* This part must be outside protection */
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 02/14] f2fs: sysfs: introduce max_lock_elapsed_time
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 03/14] f2fs: trace elapsed time for cp_rwsem lock Chao Yu
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

This patch add a new sysfs node in /sys/fs/f2fs/<device>/max_lock_elapsed_time.

This is a threshold, once a thread enters critical region that lock covers,
total elapsed time exceeds this threshold, f2fs will print tracepoint to dump
information of related context. This sysfs entry can be used to control the
value of threshold, by default, the value is 500 ms.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 8 ++++++++
 fs/f2fs/checkpoint.c                    | 2 +-
 fs/f2fs/f2fs.h                          | 3 +++
 fs/f2fs/super.c                         | 1 +
 fs/f2fs/sysfs.c                         | 2 ++
 5 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index c39a85e84b6b..648ddd0d59f6 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -939,3 +939,11 @@ Description:	Controls write priority in multi-devices setups. A value of 0 means
 		allocate_section_policy = 1  Prioritize writing to section before allocate_section_hint
 		allocate_section_policy = 2  Prioritize writing to section after allocate_section_hint
 		===========================  ==========================================================
+
+What:		/sys/fs/f2fs/<disk>/max_lock_elapsed_time
+Date:		December 2025
+Contact:	"Chao Yu" <chao@kernel.org>
+Description:	This is a threshold, once a thread enters critical region that lock covers, total
+		elapsed time exceeds this threshold, f2fs will print tracepoint to dump information
+		of related context. This sysfs entry can be used to control the value of threshold,
+		by default, the value is 500 ms.
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index bc6058a3122b..61bcf227d8ca 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -66,7 +66,7 @@ static inline void trace_lock_elapsed_time_end(struct f2fs_rwsem *sem,
 	get_lock_elapsed_time(&tts);
 
 	total_time = div_u64(tts.total_time - lc->ts.total_time, npm);
-	if (total_time <= MAX_LOCK_ELAPSED_TIME)
+	if (total_time <= sem->sbi->max_lock_elapsed_time)
 		return;
 
 #ifdef CONFIG_64BIT
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 7e22315dbedd..b31589e5e19f 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1951,6 +1951,9 @@ struct f2fs_sb_info {
 	/* carve out reserved_blocks from total blocks */
 	bool carve_out;
 
+	/* max elapsed time threshold in critical region that lock covered */
+	unsigned long long max_lock_elapsed_time;
+
 #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 */
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 16293b0f4480..d277f082d4c0 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4295,6 +4295,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
 	sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
 	spin_lock_init(&sbi->gc_remaining_trials_lock);
 	atomic64_set(&sbi->current_atomic_write, 0);
+	sbi->max_lock_elapsed_time = MAX_LOCK_ELAPSED_TIME;
 
 	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 e6a98ddd73b3..e95aa23c5bef 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -1263,6 +1263,7 @@ F2FS_SBI_GENERAL_RW_ATTR(blkzone_alloc_policy);
 F2FS_SBI_GENERAL_RW_ATTR(carve_out);
 F2FS_SBI_GENERAL_RW_ATTR(reserved_pin_section);
 F2FS_SBI_GENERAL_RW_ATTR(bggc_io_aware);
+F2FS_SBI_GENERAL_RW_ATTR(max_lock_elapsed_time);
 
 /* STAT_INFO ATTR */
 #ifdef CONFIG_F2FS_STAT_FS
@@ -1466,6 +1467,7 @@ static struct attribute *f2fs_attrs[] = {
 	ATTR_LIST(reserved_pin_section),
 	ATTR_LIST(allocate_section_hint),
 	ATTR_LIST(allocate_section_policy),
+	ATTR_LIST(max_lock_elapsed_time),
 	NULL,
 };
 ATTRIBUTE_GROUPS(f2fs);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 03/14] f2fs: trace elapsed time for cp_rwsem lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
  2026-01-04  2:07 ` [PATCH 02/14] f2fs: sysfs: introduce max_lock_elapsed_time Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 04/14] f2fs: trace elapsed time for node_change lock Chao Yu
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_read_trace for cp_rwsem to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/checkpoint.c        | 28 ++++++++++++++++
 fs/f2fs/compress.c          | 12 ++++---
 fs/f2fs/data.c              | 47 ++++++++++++++++-----------
 fs/f2fs/f2fs.h              | 33 +++----------------
 fs/f2fs/file.c              | 65 ++++++++++++++++++++++---------------
 fs/f2fs/gc.c                |  5 +--
 fs/f2fs/inline.c            | 10 +++---
 fs/f2fs/inode.c             | 10 +++---
 fs/f2fs/namei.c             | 65 +++++++++++++++++++++----------------
 fs/f2fs/segment.c           | 10 +++---
 fs/f2fs/super.c             |  7 ++--
 fs/f2fs/xattr.c             |  5 +--
 include/trace/events/f2fs.h |  2 +-
 13 files changed, 173 insertions(+), 126 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 61bcf227d8ca..dfd54cba1b35 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -127,6 +127,34 @@ void f2fs_up_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
 	trace_lock_elapsed_time_end(sem, lc, true);
 }
 
+void f2fs_lock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc)
+{
+	f2fs_down_read_trace(&sbi->cp_rwsem, lc);
+}
+
+int f2fs_trylock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc)
+{
+	if (time_to_inject(sbi, FAULT_LOCK_OP))
+		return 0;
+
+	return f2fs_down_read_trylock_trace(&sbi->cp_rwsem, lc);
+}
+
+void f2fs_unlock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc)
+{
+	f2fs_up_read_trace(&sbi->cp_rwsem, lc);
+}
+
+static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
+{
+	f2fs_down_write(&sbi->cp_rwsem);
+}
+
+static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
+{
+	f2fs_up_write(&sbi->cp_rwsem);
+}
+
 #define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 3))
 
 static struct kmem_cache *ino_entry_slab;
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7b68bf22989d..3155d30b2448 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1290,6 +1290,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 	struct dnode_of_data dn;
 	struct node_info ni;
 	struct compress_io_ctx *cic;
+	struct f2fs_lock_context lc;
 	pgoff_t start_idx = start_idx_of_cluster(cc);
 	unsigned int last_index = cc->cluster_size - 1;
 	loff_t psize;
@@ -1309,7 +1310,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 		 * the below discard race condition.
 		 */
 		f2fs_down_read(&sbi->node_write);
-	} else if (!f2fs_trylock_op(sbi)) {
+	} else if (!f2fs_trylock_op(sbi, &lc)) {
 		goto out_free;
 	}
 
@@ -1435,7 +1436,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 	if (quota_inode)
 		f2fs_up_read(&sbi->node_write);
 	else
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 
 	spin_lock(&fi->i_size_lock);
 	if (fi->last_disk_size < psize)
@@ -1464,7 +1465,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 	if (quota_inode)
 		f2fs_up_read(&sbi->node_write);
 	else
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 out_free:
 	for (i = 0; i < cc->valid_nr_cpages; i++) {
 		f2fs_compress_free_page(cc->cpages[i]);
@@ -1511,6 +1512,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 {
 	struct address_space *mapping = cc->inode->i_mapping;
 	struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
+	struct f2fs_lock_context lc;
 	int submitted, compr_blocks, i;
 	int ret = 0;
 
@@ -1529,7 +1531,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 
 	/* overwrite compressed cluster w/ normal cluster */
 	if (compr_blocks > 0)
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 	for (i = 0; i < cc->cluster_size; i++) {
 		struct folio *folio;
@@ -1585,7 +1587,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
 
 out:
 	if (compr_blocks > 0)
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 
 	f2fs_balance_fs(sbi, true);
 	return ret;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 471e52c6c1e0..73fcafbc8191 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1466,34 +1466,39 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
 	return 0;
 }
 
-static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag)
+static void f2fs_map_lock(struct f2fs_sb_info *sbi,
+				struct f2fs_lock_context *lc,
+				int flag)
 {
 	f2fs_down_read(&sbi->cp_enable_rwsem);
 	if (flag == F2FS_GET_BLOCK_PRE_AIO)
 		f2fs_down_read(&sbi->node_change);
 	else
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, lc);
 }
 
-static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag)
+static void f2fs_map_unlock(struct f2fs_sb_info *sbi,
+				struct f2fs_lock_context *lc,
+				int flag)
 {
 	if (flag == F2FS_GET_BLOCK_PRE_AIO)
 		f2fs_up_read(&sbi->node_change);
 	else
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, lc);
 	f2fs_up_read(&sbi->cp_enable_rwsem);
 }
 
 int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
+	struct f2fs_lock_context lc;
 	int err = 0;
 
-	f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+	f2fs_map_lock(sbi, &lc, F2FS_GET_BLOCK_PRE_AIO);
 	if (!f2fs_lookup_read_extent_cache_block(dn->inode, index,
 						&dn->data_blkaddr))
 		err = f2fs_reserve_block(dn, index);
-	f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+	f2fs_map_unlock(sbi, &lc, F2FS_GET_BLOCK_PRE_AIO);
 
 	return err;
 }
@@ -1584,6 +1589,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
 	unsigned int maxblocks = map->m_len;
 	struct dnode_of_data dn;
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	struct f2fs_lock_context lc;
 	int mode = map->m_may_create ? ALLOC_NODE : LOOKUP_NODE;
 	pgoff_t pgofs, end_offset, end;
 	int err = 0, ofs = 1;
@@ -1622,7 +1628,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
 	if (map->m_may_create) {
 		if (f2fs_lfs_mode(sbi))
 			f2fs_balance_fs(sbi, true);
-		f2fs_map_lock(sbi, flag);
+		f2fs_map_lock(sbi, &lc, flag);
 	}
 
 	/* When reading holes, we need its node page */
@@ -1788,7 +1794,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
 	f2fs_put_dnode(&dn);
 
 	if (map->m_may_create) {
-		f2fs_map_unlock(sbi, flag);
+		f2fs_map_unlock(sbi, &lc, flag);
 		f2fs_balance_fs(sbi, dn.node_changed);
 	}
 	goto next_dnode;
@@ -1835,7 +1841,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
 	f2fs_put_dnode(&dn);
 unlock_out:
 	if (map->m_may_create) {
-		f2fs_map_unlock(sbi, flag);
+		f2fs_map_unlock(sbi, &lc, flag);
 		f2fs_balance_fs(sbi, dn.node_changed);
 	}
 out:
@@ -2865,6 +2871,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 	struct inode *inode = folio->mapping->host;
 	struct dnode_of_data dn;
 	struct node_info ni;
+	struct f2fs_lock_context lc;
 	bool ipu_force = false;
 	bool atomic_commit;
 	int err = 0;
@@ -2890,7 +2897,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 	}
 
 	/* Deadlock due to between page->lock and f2fs_lock_op */
-	if (fio->need_lock == LOCK_REQ && !f2fs_trylock_op(fio->sbi))
+	if (fio->need_lock == LOCK_REQ && !f2fs_trylock_op(fio->sbi, &lc))
 		return -EAGAIN;
 
 	err = f2fs_get_dnode_of_data(&dn, folio->index, LOOKUP_NODE);
@@ -2931,7 +2938,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 		folio_start_writeback(folio);
 		f2fs_put_dnode(&dn);
 		if (fio->need_lock == LOCK_REQ)
-			f2fs_unlock_op(fio->sbi);
+			f2fs_unlock_op(fio->sbi, &lc);
 		err = f2fs_inplace_write_data(fio);
 		if (err) {
 			if (fscrypt_inode_uses_fs_layer_crypto(inode))
@@ -2945,7 +2952,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 	}
 
 	if (fio->need_lock == LOCK_RETRY) {
-		if (!f2fs_trylock_op(fio->sbi)) {
+		if (!f2fs_trylock_op(fio->sbi, &lc)) {
 			err = -EAGAIN;
 			goto out_writepage;
 		}
@@ -2977,7 +2984,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
 	f2fs_put_dnode(&dn);
 out:
 	if (fio->need_lock == LOCK_REQ)
-		f2fs_unlock_op(fio->sbi);
+		f2fs_unlock_op(fio->sbi, &lc);
 	return err;
 }
 
@@ -3570,6 +3577,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
 	struct inode *inode = folio->mapping->host;
 	pgoff_t index = folio->index;
 	struct dnode_of_data dn;
+	struct f2fs_lock_context lc;
 	struct folio *ifolio;
 	bool locked = false;
 	int flag = F2FS_GET_BLOCK_PRE_AIO;
@@ -3586,10 +3594,10 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
 	if (f2fs_has_inline_data(inode)) {
 		if (pos + len > MAX_INLINE_DATA(inode))
 			flag = F2FS_GET_BLOCK_DEFAULT;
-		f2fs_map_lock(sbi, flag);
+		f2fs_map_lock(sbi, &lc, flag);
 		locked = true;
 	} else if ((pos & PAGE_MASK) >= i_size_read(inode)) {
-		f2fs_map_lock(sbi, flag);
+		f2fs_map_lock(sbi, &lc, flag);
 		locked = true;
 	}
 
@@ -3633,7 +3641,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
 		if (!err && dn.data_blkaddr != NULL_ADDR)
 			goto out;
 		f2fs_put_dnode(&dn);
-		f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+		f2fs_map_lock(sbi, &lc, F2FS_GET_BLOCK_PRE_AIO);
 		WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
 		locked = true;
 		goto restart;
@@ -3647,7 +3655,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
 	f2fs_put_dnode(&dn);
 unlock_out:
 	if (locked)
-		f2fs_map_unlock(sbi, flag);
+		f2fs_map_unlock(sbi, &lc, flag);
 	return err;
 }
 
@@ -3683,10 +3691,11 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index,
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct dnode_of_data dn;
+	struct f2fs_lock_context lc;
 	struct folio *ifolio;
 	int err = 0;
 
-	f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+	f2fs_map_lock(sbi, &lc, F2FS_GET_BLOCK_PRE_AIO);
 
 	ifolio = f2fs_get_inode_folio(sbi, inode->i_ino);
 	if (IS_ERR(ifolio)) {
@@ -3704,7 +3713,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index,
 	f2fs_put_dnode(&dn);
 
 unlock_out:
-	f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+	f2fs_map_unlock(sbi, &lc, F2FS_GET_BLOCK_PRE_AIO);
 	return err;
 }
 
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index b31589e5e19f..03f5eb7549a6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -175,6 +175,7 @@ enum device_allocation_policy {
 
 enum f2fs_lock_name {
 	LOCK_NAME_NONE,
+	LOCK_NAME_CP_RWSEM,
 };
 
 /*
@@ -2417,33 +2418,6 @@ static inline bool enabled_nat_bits(struct f2fs_sb_info *sbi,
 	return (cpc) ? (cpc->reason & CP_UMOUNT) && set : set;
 }
 
-static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
-{
-	f2fs_down_read(&sbi->cp_rwsem);
-}
-
-static inline int f2fs_trylock_op(struct f2fs_sb_info *sbi)
-{
-	if (time_to_inject(sbi, FAULT_LOCK_OP))
-		return 0;
-	return f2fs_down_read_trylock(&sbi->cp_rwsem);
-}
-
-static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
-{
-	f2fs_up_read(&sbi->cp_rwsem);
-}
-
-static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
-{
-	f2fs_down_write(&sbi->cp_rwsem);
-}
-
-static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
-{
-	f2fs_up_write(&sbi->cp_rwsem);
-}
-
 static inline int __get_cp_reason(struct f2fs_sb_info *sbi)
 {
 	int reason = CP_SYNC;
@@ -3770,7 +3744,7 @@ void f2fs_update_inode_page(struct inode *inode);
 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc);
 void f2fs_remove_donate_inode(struct inode *inode);
 void f2fs_evict_inode(struct inode *inode);
-void f2fs_handle_failed_inode(struct inode *inode);
+void f2fs_handle_failed_inode(struct inode *inode, struct f2fs_lock_context *lc);
 
 /*
  * namei.c
@@ -4037,6 +4011,9 @@ static inline bool f2fs_need_rand_seg(struct f2fs_sb_info *sbi)
 /*
  * checkpoint.c
  */
+void f2fs_lock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc);
+int f2fs_trylock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc);
+void f2fs_unlock_op(struct f2fs_sb_info *sbi, struct f2fs_lock_context *lc);
 void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io,
 							unsigned char reason);
 void f2fs_flush_ckpt_thread(struct f2fs_sb_info *sbi);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index e75e61ac50d7..1cdbbc2e1005 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -774,6 +774,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct dnode_of_data dn;
+	struct f2fs_lock_context lc;
 	pgoff_t free_from;
 	int count = 0, err = 0;
 	struct folio *ifolio;
@@ -792,7 +793,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
 		goto free_partial;
 
 	if (lock)
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 	ifolio = f2fs_get_inode_folio(sbi, inode->i_ino);
 	if (IS_ERR(ifolio)) {
@@ -843,7 +844,7 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
 	err = f2fs_truncate_inode_blocks(inode, free_from);
 out:
 	if (lock)
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 free_partial:
 	/* lastly zero out the first data page */
 	if (!err)
@@ -1118,11 +1119,13 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 	}
 	if (i_uid_needs_update(idmap, attr, inode) ||
 	    i_gid_needs_update(idmap, attr, inode)) {
-		f2fs_lock_op(sbi);
+		struct f2fs_lock_context lc;
+
+		f2fs_lock_op(sbi, &lc);
 		err = dquot_transfer(idmap, inode, attr);
 		if (err) {
 			set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 			return err;
 		}
 		/*
@@ -1132,7 +1135,7 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
 		i_uid_update(idmap, attr, inode);
 		i_gid_update(idmap, attr, inode);
 		f2fs_mark_inode_dirty_sync(inode, true);
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 	}
 
 	if (attr->ia_valid & ATTR_SIZE) {
@@ -1216,15 +1219,16 @@ static int fill_zero(struct inode *inode, pgoff_t index,
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct folio *folio;
+	struct f2fs_lock_context lc;
 
 	if (!len)
 		return 0;
 
 	f2fs_balance_fs(sbi, true);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	folio = f2fs_get_new_data_folio(inode, NULL, index, false);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	if (IS_ERR(folio))
 		return PTR_ERR(folio);
@@ -1307,6 +1311,7 @@ static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 		if (pg_start < pg_end) {
 			loff_t blk_start, blk_end;
 			struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+			struct f2fs_lock_context lc;
 
 			f2fs_balance_fs(sbi, true);
 
@@ -1318,9 +1323,9 @@ static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
 
 			truncate_pagecache_range(inode, blk_start, blk_end - 1);
 
-			f2fs_lock_op(sbi);
+			f2fs_lock_op(sbi, &lc);
 			ret = f2fs_truncate_hole(inode, pg_start, pg_end);
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 
 			filemap_invalidate_unlock(inode->i_mapping);
 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
@@ -1552,6 +1557,7 @@ static int __exchange_data_block(struct inode *src_inode,
 static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	struct f2fs_lock_context lc;
 	pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
 	pgoff_t start = offset >> PAGE_SHIFT;
 	pgoff_t end = (offset + len) >> PAGE_SHIFT;
@@ -1565,11 +1571,11 @@ static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
 
 	f2fs_zero_post_eof_page(inode, offset + len, false);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	f2fs_drop_extent_tree(inode);
 	truncate_pagecache(inode, offset);
 	ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	filemap_invalidate_unlock(inode->i_mapping);
 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
@@ -1717,6 +1723,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
 
 		for (index = pg_start; index < pg_end;) {
 			struct dnode_of_data dn;
+			struct f2fs_lock_context lc;
 			unsigned int end_offset;
 			pgoff_t end;
 
@@ -1727,12 +1734,12 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
 				(loff_t)index << PAGE_SHIFT,
 				((loff_t)pg_end << PAGE_SHIFT) - 1);
 
-			f2fs_lock_op(sbi);
+			f2fs_lock_op(sbi, &lc);
 
 			set_new_dnode(&dn, inode, NULL, NULL, 0);
 			ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
 			if (ret) {
-				f2fs_unlock_op(sbi);
+				f2fs_unlock_op(sbi, &lc);
 				filemap_invalidate_unlock(mapping);
 				f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 				goto out;
@@ -1744,7 +1751,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
 			ret = f2fs_do_zero_range(&dn, index, end);
 			f2fs_put_dnode(&dn);
 
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 			filemap_invalidate_unlock(mapping);
 			f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
 
@@ -1827,17 +1834,19 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
 	truncate_pagecache(inode, offset);
 
 	while (!ret && idx > pg_start) {
+		struct f2fs_lock_context lc;
+
 		nr = idx - pg_start;
 		if (nr > delta)
 			nr = delta;
 		idx -= nr;
 
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 		f2fs_drop_extent_tree(inode);
 
 		ret = __exchange_data_block(inode, inode, idx,
 					idx + delta, nr, false);
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 	}
 	filemap_invalidate_unlock(mapping);
 	f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
@@ -3093,6 +3102,7 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
 	struct inode *src = file_inode(file_in);
 	struct inode *dst = file_inode(file_out);
 	struct f2fs_sb_info *sbi = F2FS_I_SB(src);
+	struct f2fs_lock_context lc;
 	size_t olen = len, dst_max_i_size = 0;
 	size_t dst_osize;
 	int ret;
@@ -3188,7 +3198,7 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
 			goto out_src;
 	}
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	ret = __exchange_data_block(src, dst, F2FS_BYTES_TO_BLK(pos_in),
 				F2FS_BYTES_TO_BLK(pos_out),
 				F2FS_BYTES_TO_BLK(len), false);
@@ -3199,7 +3209,7 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
 		else if (dst_osize != dst->i_size)
 			f2fs_i_size_write(dst, dst_osize);
 	}
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	if (src != dst)
 		f2fs_up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
@@ -3367,6 +3377,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct f2fs_inode *ri = NULL;
+	struct f2fs_lock_context lc;
 	kprojid_t kprojid;
 	int err;
 
@@ -3397,7 +3408,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
 	if (err)
 		return err;
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_transfer_project_quota(inode, kprojid);
 	if (err)
 		goto out_unlock;
@@ -3406,7 +3417,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
 	inode_set_ctime_current(inode);
 	f2fs_mark_inode_dirty_sync(inode, true);
 out_unlock:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	return err;
 }
 #else
@@ -3839,6 +3850,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
 	struct inode *inode = file_inode(filp);
 	struct f2fs_inode_info *fi = F2FS_I(inode);
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	struct f2fs_lock_context lc;
 	pgoff_t page_idx = 0, last_idx;
 	unsigned int released_blocks = 0;
 	int ret;
@@ -3893,12 +3905,12 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
 		struct dnode_of_data dn;
 		pgoff_t end_offset, count;
 
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 		set_new_dnode(&dn, inode, NULL, NULL, 0);
 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
 		if (ret) {
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 			if (ret == -ENOENT) {
 				page_idx = f2fs_get_next_page_offset(&dn,
 								page_idx);
@@ -3916,7 +3928,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
 
 		f2fs_put_dnode(&dn);
 
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 
 		if (ret < 0)
 			break;
@@ -4069,14 +4081,15 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
 
 	while (page_idx < last_idx) {
 		struct dnode_of_data dn;
+		struct f2fs_lock_context lc;
 		pgoff_t end_offset, count;
 
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 		set_new_dnode(&dn, inode, NULL, NULL, 0);
 		ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
 		if (ret) {
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 			if (ret == -ENOENT) {
 				page_idx = f2fs_get_next_page_offset(&dn,
 								page_idx);
@@ -4094,7 +4107,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
 
 		f2fs_put_dnode(&dn);
 
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 
 		if (ret < 0)
 			break;
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index ba66d8bc9b5f..8999829a9559 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -2263,6 +2263,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
 	__u64 old_block_count, shrunk_blocks;
 	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
+	struct f2fs_lock_context lc;
 	unsigned int secs;
 	int err = 0;
 	__u32 rem;
@@ -2312,7 +2313,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	}
 
 	/* stop CP to protect MAIN_SEC in free_segment_range */
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 
 	spin_lock(&sbi->stat_lock);
 	if (shrunk_blocks + valid_user_blocks(sbi) +
@@ -2327,7 +2328,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	err = free_segment_range(sbi, secs, true);
 
 out_unlock:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	f2fs_up_write(&sbi->gc_lock);
 out_drop_write:
 	mnt_drop_write_file(filp);
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index e5c6a08b7e4f..0a1052d5ee62 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -218,6 +218,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct dnode_of_data dn;
+	struct f2fs_lock_context lc;
 	struct folio *ifolio, *folio;
 	int err = 0;
 
@@ -235,7 +236,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
 	if (IS_ERR(folio))
 		return PTR_ERR(folio);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 
 	ifolio = f2fs_get_inode_folio(sbi, inode->i_ino);
 	if (IS_ERR(ifolio)) {
@@ -250,7 +251,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
 
 	f2fs_put_dnode(&dn);
 out:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	f2fs_folio_put(folio, true);
 
@@ -597,13 +598,14 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
 	struct folio *ifolio;
 	struct f2fs_filename fname;
+	struct f2fs_lock_context lc;
 	void *inline_dentry = NULL;
 	int err = 0;
 
 	if (!f2fs_has_inline_dentry(dir))
 		return 0;
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 
 	err = f2fs_setup_filename(dir, &dentry->d_name, 0, &fname);
 	if (err)
@@ -628,7 +630,7 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
 out_fname:
 	f2fs_free_filename(&fname);
 out:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	return err;
 }
 
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index d1270b25ad7d..b8cf1fab6391 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -910,9 +910,11 @@ void f2fs_evict_inode(struct inode *inode)
 		err = -EIO;
 
 	if (!err) {
-		f2fs_lock_op(sbi);
+		struct f2fs_lock_context lc;
+
+		f2fs_lock_op(sbi, &lc);
 		err = f2fs_remove_inode_page(inode);
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 		if (err == -ENOENT) {
 			err = 0;
 
@@ -1009,7 +1011,7 @@ void f2fs_evict_inode(struct inode *inode)
 }
 
 /* caller should call f2fs_lock_op() */
-void f2fs_handle_failed_inode(struct inode *inode)
+void f2fs_handle_failed_inode(struct inode *inode, struct f2fs_lock_context *lc)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct node_info ni;
@@ -1058,7 +1060,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
 	}
 
 out:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, lc);
 
 	/* iput will drop the inode object */
 	iput(inode);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 043d20516a21..e360f08a9586 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -354,6 +354,7 @@ static int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
 		       struct dentry *dentry, umode_t mode, bool excl)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	struct inode *inode;
 	nid_t ino = 0;
 	int err;
@@ -376,11 +377,11 @@ static int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
 	ino = inode->i_ino;
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
 		goto out;
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	f2fs_alloc_nid_done(sbi, ino);
 
@@ -392,7 +393,7 @@ static int f2fs_create(struct mnt_idmap *idmap, struct inode *dir,
 	f2fs_balance_fs(sbi, true);
 	return 0;
 out:
-	f2fs_handle_failed_inode(inode);
+	f2fs_handle_failed_inode(inode, &lc);
 	return err;
 }
 
@@ -401,6 +402,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
 {
 	struct inode *inode = d_inode(old_dentry);
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	int err;
 
 	if (unlikely(f2fs_cp_error(sbi)))
@@ -427,11 +429,11 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
 	ihold(inode);
 
 	set_inode_flag(inode, FI_INC_LINK);
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
 		goto out;
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	d_instantiate(dentry, inode);
 
@@ -441,7 +443,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
 out:
 	clear_inode_flag(inode, FI_INC_LINK);
 	iput(inode);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	return err;
 }
 
@@ -545,6 +547,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
 	struct inode *inode = d_inode(dentry);
 	struct f2fs_dir_entry *de;
+	struct f2fs_lock_context lc;
 	struct folio *folio;
 	int err;
 
@@ -581,15 +584,15 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
 
 	f2fs_balance_fs(sbi, true);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_acquire_orphan_inode(sbi);
 	if (err) {
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 		f2fs_folio_put(folio, false);
 		goto out;
 	}
 	f2fs_delete_entry(de, folio, dir, inode);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	/* VFS negative dentries are incompatible with Encoding and
 	 * Case-insensitiveness. Eventually we'll want avoid
@@ -632,6 +635,7 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir,
 			struct dentry *dentry, const char *symname)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	struct inode *inode;
 	size_t len = strlen(symname);
 	struct fscrypt_str disk_link;
@@ -662,11 +666,11 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir,
 	inode_nohighmem(inode);
 	inode->i_mapping->a_ops = &f2fs_dblock_aops;
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
 		goto out_f2fs_handle_failed_inode;
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	f2fs_alloc_nid_done(sbi, inode->i_ino);
 
 	err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
@@ -701,7 +705,7 @@ static int f2fs_symlink(struct mnt_idmap *idmap, struct inode *dir,
 	goto out_free_encrypted_link;
 
 out_f2fs_handle_failed_inode:
-	f2fs_handle_failed_inode(inode);
+	f2fs_handle_failed_inode(inode, &lc);
 out_free_encrypted_link:
 	if (disk_link.name != (unsigned char *)symname)
 		kfree(disk_link.name);
@@ -712,6 +716,7 @@ static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
 				 struct dentry *dentry, umode_t mode)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	struct inode *inode;
 	int err;
 
@@ -732,11 +737,11 @@ static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
 	mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
 
 	set_inode_flag(inode, FI_INC_LINK);
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
 		goto out_fail;
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	f2fs_alloc_nid_done(sbi, inode->i_ino);
 
@@ -750,7 +755,7 @@ static struct dentry *f2fs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
 
 out_fail:
 	clear_inode_flag(inode, FI_INC_LINK);
-	f2fs_handle_failed_inode(inode);
+	f2fs_handle_failed_inode(inode, &lc);
 	return ERR_PTR(err);
 }
 
@@ -767,6 +772,7 @@ static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir,
 		      struct dentry *dentry, umode_t mode, dev_t rdev)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	struct inode *inode;
 	int err = 0;
 
@@ -786,11 +792,11 @@ static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir,
 	init_special_inode(inode, inode->i_mode, rdev);
 	inode->i_op = &f2fs_special_inode_operations;
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_add_link(dentry, inode);
 	if (err)
 		goto out;
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	f2fs_alloc_nid_done(sbi, inode->i_ino);
 
@@ -802,7 +808,7 @@ static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir,
 	f2fs_balance_fs(sbi, true);
 	return 0;
 out:
-	f2fs_handle_failed_inode(inode);
+	f2fs_handle_failed_inode(inode, &lc);
 	return err;
 }
 
@@ -811,6 +817,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
 			  struct inode **new_inode, struct f2fs_filename *fname)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+	struct f2fs_lock_context lc;
 	struct inode *inode;
 	int err;
 
@@ -831,7 +838,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
 		inode->i_mapping->a_ops = &f2fs_dblock_aops;
 	}
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_acquire_orphan_inode(sbi);
 	if (err)
 		goto out;
@@ -860,7 +867,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
 			f2fs_i_links_write(inode, false);
 	}
 	/* link_count was changed by d_tmpfile as well. */
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	unlock_new_inode(inode);
 
 	if (new_inode)
@@ -872,7 +879,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
 release_out:
 	f2fs_release_orphan_inode(sbi);
 out:
-	f2fs_handle_failed_inode(inode);
+	f2fs_handle_failed_inode(inode, &lc);
 	return err;
 }
 
@@ -920,6 +927,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 	struct f2fs_dir_entry *old_dir_entry = NULL;
 	struct f2fs_dir_entry *old_entry;
 	struct f2fs_dir_entry *new_entry;
+	struct f2fs_lock_context lc;
 	bool old_is_dir = S_ISDIR(old_inode->i_mode);
 	int err;
 
@@ -1008,7 +1016,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 
 		f2fs_balance_fs(sbi, true);
 
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 		err = f2fs_acquire_orphan_inode(sbi);
 		if (err)
@@ -1031,11 +1039,11 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 	} else {
 		f2fs_balance_fs(sbi, true);
 
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 
 		err = f2fs_add_link(new_dentry, old_inode);
 		if (err) {
-			f2fs_unlock_op(sbi);
+			f2fs_unlock_op(sbi, &lc);
 			goto out_dir;
 		}
 
@@ -1084,7 +1092,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 							TRANS_DIR_INO);
 	}
 
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
 		f2fs_sync_fs(sbi->sb, 1);
@@ -1093,7 +1101,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
 	return 0;
 
 put_out_dir:
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	f2fs_folio_put(new_folio, false);
 out_dir:
 	if (old_dir_entry)
@@ -1115,6 +1123,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct folio *old_folio, *new_folio;
 	struct f2fs_dir_entry *old_dir_entry = NULL, *new_dir_entry = NULL;
 	struct f2fs_dir_entry *old_entry, *new_entry;
+	struct f2fs_lock_context lc;
 	int old_nlink = 0, new_nlink = 0;
 	int err;
 
@@ -1194,7 +1203,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 	f2fs_balance_fs(sbi, true);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 
 	/* update ".." directory entry info of old dentry */
 	if (old_dir_entry)
@@ -1247,7 +1256,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 		f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
 	}
 
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
 		f2fs_sync_fs(sbi->sb, 1);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index c0c5b7075b04..e4a8daf433a8 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -400,6 +400,7 @@ int f2fs_commit_atomic_write(struct inode *inode)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
 	struct f2fs_inode_info *fi = F2FS_I(inode);
+	struct f2fs_lock_context lc;
 	int err;
 
 	err = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
@@ -407,11 +408,11 @@ int f2fs_commit_atomic_write(struct inode *inode)
 		return err;
 
 	f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 
 	err = __f2fs_commit_atomic_write(inode);
 
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 	f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
 
 	return err;
@@ -3362,13 +3363,14 @@ int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)
 
 int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
 {
+	struct f2fs_lock_context lc;
 	int err;
 	bool gc_required = true;
 
 retry:
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	err = f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
 		f2fs_down_write(&sbi->gc_lock);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index d277f082d4c0..d60b91292c23 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -3325,6 +3325,7 @@ int f2fs_do_quota_sync(struct super_block *sb, int type)
 	 * that userspace sees the changes.
 	 */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		struct f2fs_lock_context lc;
 
 		if (type != -1 && cnt != type)
 			continue;
@@ -3344,13 +3345,13 @@ int f2fs_do_quota_sync(struct super_block *sb, int type)
 		 *			      block_operation
 		 *			      f2fs_down_read(quota_sem)
 		 */
-		f2fs_lock_op(sbi);
+		f2fs_lock_op(sbi, &lc);
 		f2fs_down_read(&sbi->quota_sem);
 
 		ret = f2fs_quota_sync_file(sbi, cnt);
 
 		f2fs_up_read(&sbi->quota_sem);
-		f2fs_unlock_op(sbi);
+		f2fs_unlock_op(sbi, &lc);
 
 		if (!f2fs_sb_has_quota_ino(sbi))
 			inode_unlock(dqopt->files[cnt]);
@@ -4898,7 +4899,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	init_f2fs_rwsem(&sbi->node_write);
 	init_f2fs_rwsem(&sbi->node_change);
 	spin_lock_init(&sbi->stat_lock);
-	init_f2fs_rwsem(&sbi->cp_rwsem);
+	init_f2fs_rwsem_trace(&sbi->cp_rwsem, sbi, LOCK_NAME_CP_RWSEM);
 	init_f2fs_rwsem(&sbi->cp_enable_rwsem);
 	init_f2fs_rwsem(&sbi->quota_sem);
 	init_waitqueue_head(&sbi->cp_wait);
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index b4e5c406632f..941dc62a6d6f 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -804,6 +804,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
 				struct folio *ifolio, int flags)
 {
 	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+	struct f2fs_lock_context lc;
 	int err;
 
 	if (unlikely(f2fs_cp_error(sbi)))
@@ -821,11 +822,11 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
 						size, ifolio, flags);
 	f2fs_balance_fs(sbi, true);
 
-	f2fs_lock_op(sbi);
+	f2fs_lock_op(sbi, &lc);
 	f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
 	err = __f2fs_setxattr(inode, index, name, value, size, NULL, flags);
 	f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
-	f2fs_unlock_op(sbi);
+	f2fs_unlock_op(sbi, &lc);
 
 	f2fs_update_time(sbi, REQ_TIME);
 	return err;
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 9a852a16df9c..f4f13ddbe104 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -186,7 +186,7 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 
 #define show_lock_name(lock)						\
 	__print_symbolic(lock,						\
-		{ LOCK_NAME_NONE,		"none" })
+		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 04/14] f2fs: trace elapsed time for node_change lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
  2026-01-04  2:07 ` [PATCH 02/14] f2fs: sysfs: introduce max_lock_elapsed_time Chao Yu
  2026-01-04  2:07 ` [PATCH 03/14] f2fs: trace elapsed time for cp_rwsem lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 05/14] f2fs: trace elapsed time for node_write lock Chao Yu
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_read_trace for node_change to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/data.c              | 4 ++--
 fs/f2fs/f2fs.h              | 1 +
 fs/f2fs/super.c             | 2 +-
 include/trace/events/f2fs.h | 3 ++-
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 73fcafbc8191..5469547142e7 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1472,7 +1472,7 @@ static void f2fs_map_lock(struct f2fs_sb_info *sbi,
 {
 	f2fs_down_read(&sbi->cp_enable_rwsem);
 	if (flag == F2FS_GET_BLOCK_PRE_AIO)
-		f2fs_down_read(&sbi->node_change);
+		f2fs_down_read_trace(&sbi->node_change, lc);
 	else
 		f2fs_lock_op(sbi, lc);
 }
@@ -1482,7 +1482,7 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi,
 				int flag)
 {
 	if (flag == F2FS_GET_BLOCK_PRE_AIO)
-		f2fs_up_read(&sbi->node_change);
+		f2fs_up_read_trace(&sbi->node_change, lc);
 	else
 		f2fs_unlock_op(sbi, lc);
 	f2fs_up_read(&sbi->cp_enable_rwsem);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 03f5eb7549a6..972cff745e63 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -176,6 +176,7 @@ enum device_allocation_policy {
 enum f2fs_lock_name {
 	LOCK_NAME_NONE,
 	LOCK_NAME_CP_RWSEM,
+	LOCK_NAME_NODE_CHANGE,
 };
 
 /*
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index d60b91292c23..0d406fc8bc22 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4897,7 +4897,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	mutex_init(&sbi->writepages);
 	init_f2fs_rwsem(&sbi->cp_global_sem);
 	init_f2fs_rwsem(&sbi->node_write);
-	init_f2fs_rwsem(&sbi->node_change);
+	init_f2fs_rwsem_trace(&sbi->node_change, sbi, LOCK_NAME_NODE_CHANGE);
 	spin_lock_init(&sbi->stat_lock);
 	init_f2fs_rwsem_trace(&sbi->cp_rwsem, sbi, LOCK_NAME_CP_RWSEM);
 	init_f2fs_rwsem(&sbi->cp_enable_rwsem);
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index f4f13ddbe104..d472f47eedec 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -186,7 +186,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 
 #define show_lock_name(lock)						\
 	__print_symbolic(lock,						\
-		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" })
+		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
+		{ LOCK_NAME_NODE_CHANGE,	"node_change" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 05/14] f2fs: trace elapsed time for node_write lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (2 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 04/14] f2fs: trace elapsed time for node_change lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock Chao Yu
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_read_trace for node_write to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/compress.c          | 6 +++---
 fs/f2fs/data.c              | 6 ++++--
 fs/f2fs/f2fs.h              | 1 +
 fs/f2fs/node.c              | 9 +++++----
 fs/f2fs/super.c             | 2 +-
 include/trace/events/f2fs.h | 3 ++-
 6 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 3155d30b2448..316bc3e6d2d4 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1309,7 +1309,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 		 * checkpoint. This can only happen to quota writes which can cause
 		 * the below discard race condition.
 		 */
-		f2fs_down_read(&sbi->node_write);
+		f2fs_down_read_trace(&sbi->node_write, &lc);
 	} else if (!f2fs_trylock_op(sbi, &lc)) {
 		goto out_free;
 	}
@@ -1434,7 +1434,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 
 	f2fs_put_dnode(&dn);
 	if (quota_inode)
-		f2fs_up_read(&sbi->node_write);
+		f2fs_up_read_trace(&sbi->node_write, &lc);
 	else
 		f2fs_unlock_op(sbi, &lc);
 
@@ -1463,7 +1463,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
 	f2fs_put_dnode(&dn);
 out_unlock_op:
 	if (quota_inode)
-		f2fs_up_read(&sbi->node_write);
+		f2fs_up_read_trace(&sbi->node_write, &lc);
 	else
 		f2fs_unlock_op(sbi, &lc);
 out_free:
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 5469547142e7..79455d7acba5 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -3064,19 +3064,21 @@ int f2fs_write_single_data_page(struct folio *folio, int *submitted,
 write:
 	/* Dentry/quota blocks are controlled by checkpoint */
 	if (S_ISDIR(inode->i_mode) || quota_inode) {
+		struct f2fs_lock_context lc;
+
 		/*
 		 * We need to wait for node_write to avoid block allocation during
 		 * checkpoint. This can only happen to quota writes which can cause
 		 * the below discard race condition.
 		 */
 		if (quota_inode)
-			f2fs_down_read(&sbi->node_write);
+			f2fs_down_read_trace(&sbi->node_write, &lc);
 
 		fio.need_lock = LOCK_DONE;
 		err = f2fs_do_write_data_page(&fio);
 
 		if (quota_inode)
-			f2fs_up_read(&sbi->node_write);
+			f2fs_up_read_trace(&sbi->node_write, &lc);
 
 		goto done;
 	}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 972cff745e63..3f6278ba620d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -177,6 +177,7 @@ enum f2fs_lock_name {
 	LOCK_NAME_NONE,
 	LOCK_NAME_CP_RWSEM,
 	LOCK_NAME_NODE_CHANGE,
+	LOCK_NAME_NODE_WRITE,
 };
 
 /*
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index ecba9b0836eb..99e425e8c00a 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1738,6 +1738,7 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
 		.io_type = io_type,
 		.io_wbc = wbc,
 	};
+	struct f2fs_lock_context lc;
 	unsigned int seq;
 
 	trace_f2fs_writepage(folio, NODE);
@@ -1767,13 +1768,13 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
 	if (f2fs_get_node_info(sbi, nid, &ni, !do_balance))
 		goto redirty_out;
 
-	f2fs_down_read(&sbi->node_write);
+	f2fs_down_read_trace(&sbi->node_write, &lc);
 
 	/* This page is already truncated */
 	if (unlikely(ni.blk_addr == NULL_ADDR)) {
 		folio_clear_uptodate(folio);
 		dec_page_count(sbi, F2FS_DIRTY_NODES);
-		f2fs_up_read(&sbi->node_write);
+		f2fs_up_read_trace(&sbi->node_write, &lc);
 		folio_unlock(folio);
 		return true;
 	}
@@ -1781,7 +1782,7 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
 	if (__is_valid_data_blkaddr(ni.blk_addr) &&
 		!f2fs_is_valid_blkaddr(sbi, ni.blk_addr,
 					DATA_GENERIC_ENHANCE)) {
-		f2fs_up_read(&sbi->node_write);
+		f2fs_up_read_trace(&sbi->node_write, &lc);
 		goto redirty_out;
 	}
 
@@ -1806,7 +1807,7 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
 	f2fs_do_write_node_page(nid, &fio);
 	set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(folio));
 	dec_page_count(sbi, F2FS_DIRTY_NODES);
-	f2fs_up_read(&sbi->node_write);
+	f2fs_up_read_trace(&sbi->node_write, &lc);
 
 	folio_unlock(folio);
 
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 0d406fc8bc22..d8e5e8652d97 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4896,7 +4896,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	init_f2fs_rwsem(&sbi->gc_lock);
 	mutex_init(&sbi->writepages);
 	init_f2fs_rwsem(&sbi->cp_global_sem);
-	init_f2fs_rwsem(&sbi->node_write);
+	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
 	init_f2fs_rwsem_trace(&sbi->node_change, sbi, LOCK_NAME_NODE_CHANGE);
 	spin_lock_init(&sbi->stat_lock);
 	init_f2fs_rwsem_trace(&sbi->cp_rwsem, sbi, LOCK_NAME_CP_RWSEM);
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index d472f47eedec..e5cfb8ad0d5e 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -187,7 +187,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 #define show_lock_name(lock)						\
 	__print_symbolic(lock,						\
 		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
-		{ LOCK_NAME_NODE_CHANGE,	"node_change" })
+		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
+		{ LOCK_NAME_NODE_WRITE,		"node_write" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (3 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 05/14] f2fs: trace elapsed time for node_write lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  5:35   ` Jaegeuk Kim
  2026-01-04  2:07 ` [PATCH 07/14] f2fs: trace elapsed time for cp_global_sem lock Chao Yu
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_write_trace for gc_lock to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/checkpoint.c        | 10 ++++++----
 fs/f2fs/f2fs.h              | 22 ++++++++++++----------
 fs/f2fs/file.c              | 13 +++++++------
 fs/f2fs/gc.c                | 23 +++++++++++++----------
 fs/f2fs/segment.c           | 11 ++++++-----
 fs/f2fs/super.c             | 15 +++++++++------
 include/trace/events/f2fs.h |  3 ++-
 7 files changed, 55 insertions(+), 42 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index dfd54cba1b35..da7bcfa2a178 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1930,11 +1930,12 @@ void f2fs_destroy_checkpoint_caches(void)
 static int __write_checkpoint_sync(struct f2fs_sb_info *sbi)
 {
 	struct cp_control cpc = { .reason = CP_SYNC, };
+	struct f2fs_lock_context lc;
 	int err;
 
-	f2fs_down_write(&sbi->gc_lock);
+	f2fs_down_write_trace(&sbi->gc_lock, &lc);
 	err = f2fs_write_checkpoint(sbi, &cpc);
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &lc);
 
 	return err;
 }
@@ -2022,11 +2023,12 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
 	cpc.reason = __get_cp_reason(sbi);
 	if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC ||
 		sbi->umount_lock_holder == current) {
+		struct f2fs_lock_context lc;
 		int ret;
 
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &lc);
 		ret = f2fs_write_checkpoint(sbi, &cpc);
-		f2fs_up_write(&sbi->gc_lock);
+		f2fs_up_write_trace(&sbi->gc_lock, &lc);
 
 		return ret;
 	}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 3f6278ba620d..5b6e632b37a9 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -178,6 +178,7 @@ enum f2fs_lock_name {
 	LOCK_NAME_CP_RWSEM,
 	LOCK_NAME_NODE_CHANGE,
 	LOCK_NAME_NODE_WRITE,
+	LOCK_NAME_GC_LOCK,
 };
 
 /*
@@ -1408,16 +1409,6 @@ struct atgc_management {
 	unsigned long long age_threshold;	/* age threshold */
 };
 
-struct f2fs_gc_control {
-	unsigned int victim_segno;	/* target victim segment number */
-	int init_gc_type;		/* FG_GC or BG_GC */
-	bool no_bg_gc;			/* check the space and stop bg_gc */
-	bool should_migrate_blocks;	/* should migrate blocks */
-	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
-	bool one_time;			/* require one time GC in one migration unit */
-	unsigned int nr_free_secs;	/* # of free sections to do GC */
-};
-
 struct f2fs_time_stat {
 	unsigned long long total_time;		/* total wall clock time */
 #ifdef CONFIG_64BIT
@@ -1436,6 +1427,17 @@ struct f2fs_lock_context {
 	bool lock_trace;
 };
 
+struct f2fs_gc_control {
+	unsigned int victim_segno;	/* target victim segment number */
+	int init_gc_type;		/* FG_GC or BG_GC */
+	bool no_bg_gc;			/* check the space and stop bg_gc */
+	bool should_migrate_blocks;	/* should migrate blocks */
+	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
+	bool one_time;			/* require one time GC in one migration unit */
+	unsigned int nr_free_secs;	/* # of free sections to do GC */
+	struct f2fs_lock_context lc;	/* lock context for gc_lock */
+};
+
 /*
  * For s_flag in struct f2fs_sb_info
  * Modification on enum should be synchronized with s_flag array
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 1cdbbc2e1005..ce291f152bc3 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -1928,7 +1928,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
 
 		if (has_not_enough_free_secs(sbi, 0,
 				sbi->reserved_pin_section)) {
-			f2fs_down_write(&sbi->gc_lock);
+			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 			stat_inc_gc_call_count(sbi, FOREGROUND);
 			err = f2fs_gc(sbi, &gc_control);
 			if (err && err != -ENODATA) {
@@ -2779,12 +2779,13 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
 		return ret;
 
 	if (!sync) {
-		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
+		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
+						&gc_control.lc)) {
 			ret = -EBUSY;
 			goto out;
 		}
 	} else {
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 	}
 
 	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
@@ -2824,12 +2825,12 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
 
 do_more:
 	if (!range->sync) {
-		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
+		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
 			ret = -EBUSY;
 			goto out;
 		}
 	} else {
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 	}
 
 	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
@@ -3320,7 +3321,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
 	end_segno = min(start_segno + range.segments, dev_end_segno);
 
 	while (start_segno < end_segno) {
-		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
+		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
 			ret = -EBUSY;
 			goto out;
 		}
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 8999829a9559..391e66064c7e 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -102,21 +102,22 @@ static int gc_thread_func(void *data)
 		if (sbi->gc_mode == GC_URGENT_HIGH ||
 				sbi->gc_mode == GC_URGENT_MID) {
 			wait_ms = gc_th->urgent_sleep_time;
-			f2fs_down_write(&sbi->gc_lock);
+			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 			goto do_gc;
 		}
 
 		if (foreground) {
-			f2fs_down_write(&sbi->gc_lock);
+			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 			goto do_gc;
-		} else if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
+		} else if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
+							&gc_control.lc)) {
 			stat_other_skip_bggc_count(sbi);
 			goto next;
 		}
 
 		if (!is_idle(sbi, GC_TIME)) {
 			increase_sleep_time(gc_th, &wait_ms);
-			f2fs_up_write(&sbi->gc_lock);
+			f2fs_up_write_trace(&sbi->gc_lock, &gc_control.lc);
 			stat_io_skip_bggc_count(sbi);
 			goto next;
 		}
@@ -125,7 +126,8 @@ static int gc_thread_func(void *data)
 			if (has_enough_free_blocks(sbi,
 				gc_th->no_zoned_gc_percent)) {
 				wait_ms = gc_th->no_gc_sleep_time;
-				f2fs_up_write(&sbi->gc_lock);
+				f2fs_up_write_trace(&sbi->gc_lock,
+							&gc_control.lc);
 				goto next;
 			}
 			if (wait_ms == gc_th->no_gc_sleep_time)
@@ -2046,7 +2048,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
 				reserved_segments(sbi),
 				prefree_segments(sbi));
 
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &gc_control->lc);
 
 	put_gc_inode(&gc_list);
 
@@ -2264,6 +2266,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	__u64 old_block_count, shrunk_blocks;
 	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
 	struct f2fs_lock_context lc;
+	struct f2fs_lock_context glc;
 	unsigned int secs;
 	int err = 0;
 	__u32 rem;
@@ -2307,7 +2310,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi));
 
 	/* stop other GC */
-	if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
+	if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &glc)) {
 		err = -EAGAIN;
 		goto out_drop_write;
 	}
@@ -2329,7 +2332,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 
 out_unlock:
 	f2fs_unlock_op(sbi, &lc);
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &glc);
 out_drop_write:
 	mnt_drop_write_file(filp);
 	if (err)
@@ -2346,7 +2349,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 		return -EROFS;
 	}
 
-	f2fs_down_write(&sbi->gc_lock);
+	f2fs_down_write_trace(&sbi->gc_lock, &glc);
 	f2fs_down_write(&sbi->cp_global_sem);
 
 	spin_lock(&sbi->stat_lock);
@@ -2396,7 +2399,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	}
 out_err:
 	f2fs_up_write(&sbi->cp_global_sem);
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &glc);
 	thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
 	return err;
 }
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index e4a8daf433a8..776b0df828ed 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -462,7 +462,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
 			.should_migrate_blocks = false,
 			.err_gc_skipped = false,
 			.nr_free_secs = 1 };
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
 		stat_inc_gc_call_count(sbi, FOREGROUND);
 		f2fs_gc(sbi, &gc_control);
 	}
@@ -3373,10 +3373,10 @@ int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
 	f2fs_unlock_op(sbi, &lc);
 
 	if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &lc);
 		err = f2fs_gc_range(sbi, 0, sbi->first_seq_zone_segno - 1,
 				true, ZONED_PIN_SEC_REQUIRED_COUNT);
-		f2fs_up_write(&sbi->gc_lock);
+		f2fs_up_write_trace(&sbi->gc_lock, &lc);
 
 		gc_required = false;
 		if (!err)
@@ -3496,6 +3496,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
 	block_t start_block, end_block;
 	struct cp_control cpc;
 	struct discard_policy dpolicy;
+	struct f2fs_lock_context lc;
 	unsigned long long trimmed = 0;
 	int err = 0;
 	bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
@@ -3528,10 +3529,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
 	if (sbi->discard_blks == 0)
 		goto out;
 
-	f2fs_down_write(&sbi->gc_lock);
+	f2fs_down_write_trace(&sbi->gc_lock, &lc);
 	stat_inc_cp_call_count(sbi, TOTAL_CALL);
 	err = f2fs_write_checkpoint(sbi, &cpc);
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &lc);
 	if (err)
 		goto out;
 
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index d8e5e8652d97..abb468eb4394 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -2563,6 +2563,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 	int err = 0;
 	int ret;
 	block_t unusable;
+	struct f2fs_lock_context lc;
 
 	if (s_flags & SB_RDONLY) {
 		f2fs_err(sbi, "checkpoint=disable on readonly fs");
@@ -2588,9 +2589,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 			.no_bg_gc = true,
 			.nr_free_secs = 1 };
 
-		f2fs_down_write(&sbi->gc_lock);
+		f2fs_down_write_trace(&sbi->gc_lock, &lc);
 		stat_inc_gc_call_count(sbi, FOREGROUND);
 		err = f2fs_gc(sbi, &gc_control);
+		f2fs_up_write_trace(&sbi->gc_lock, &lc);
 		if (err == -ENODATA) {
 			err = 0;
 			break;
@@ -2612,7 +2614,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 	}
 
 skip_gc:
-	f2fs_down_write(&sbi->gc_lock);
+	f2fs_down_write_trace(&sbi->gc_lock, &lc);
 	cpc.reason = CP_PAUSE;
 	set_sbi_flag(sbi, SBI_CP_DISABLED);
 	stat_inc_cp_call_count(sbi, TOTAL_CALL);
@@ -2625,7 +2627,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
 	spin_unlock(&sbi->stat_lock);
 
 out_unlock:
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &lc);
 restore_flag:
 	sbi->gc_mode = gc_mode;
 	sbi->sb->s_flags = s_flags;	/* Restore SB_RDONLY status */
@@ -2638,6 +2640,7 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
 	unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16;
 	long long start, writeback, lock, sync_inode, end;
 	int ret;
+	struct f2fs_lock_context lc;
 
 	f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld",
 					__func__,
@@ -2672,12 +2675,12 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
 
 	sync_inode = ktime_get();
 
-	f2fs_down_write(&sbi->gc_lock);
+	f2fs_down_write_trace(&sbi->gc_lock, &lc);
 	f2fs_dirty_to_prefree(sbi);
 
 	clear_sbi_flag(sbi, SBI_CP_DISABLED);
 	set_sbi_flag(sbi, SBI_IS_DIRTY);
-	f2fs_up_write(&sbi->gc_lock);
+	f2fs_up_write_trace(&sbi->gc_lock, &lc);
 
 	f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld",
 					__func__,
@@ -4893,7 +4896,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	sbi->sb = sb;
 
 	/* initialize locks within allocated memory */
-	init_f2fs_rwsem(&sbi->gc_lock);
+	init_f2fs_rwsem_trace(&sbi->gc_lock, sbi, LOCK_NAME_GC_LOCK);
 	mutex_init(&sbi->writepages);
 	init_f2fs_rwsem(&sbi->cp_global_sem);
 	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index e5cfb8ad0d5e..bf353e7e024d 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -188,7 +188,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 	__print_symbolic(lock,						\
 		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
 		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
-		{ LOCK_NAME_NODE_WRITE,		"node_write" })
+		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
+		{ LOCK_NAME_GC_LOCK,		"gc_lock" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 07/14] f2fs: trace elapsed time for cp_global_sem lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (4 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 08/14] f2fs: trace elapsed time for io_rwsem lock Chao Yu
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_write_trace for cp_global_sem to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/checkpoint.c        | 10 ++++++----
 fs/f2fs/f2fs.h              |  1 +
 fs/f2fs/gc.c                |  5 +++--
 fs/f2fs/recovery.c          |  5 +++--
 fs/f2fs/super.c             |  2 +-
 include/trace/events/f2fs.h |  3 ++-
 6 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index da7bcfa2a178..86656231ce83 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -513,6 +513,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
 				struct writeback_control *wbc)
 {
 	struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
+	struct f2fs_lock_context lc;
 	long diff, written;
 
 	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
@@ -525,13 +526,13 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
 		goto skip_write;
 
 	/* if locked failed, cp will flush dirty pages instead */
-	if (!f2fs_down_write_trylock(&sbi->cp_global_sem))
+	if (!f2fs_down_write_trylock_trace(&sbi->cp_global_sem, &lc))
 		goto skip_write;
 
 	trace_f2fs_writepages(mapping->host, wbc, META);
 	diff = nr_pages_to_write(sbi, META, wbc);
 	written = f2fs_sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO);
-	f2fs_up_write(&sbi->cp_global_sem);
+	f2fs_up_write_trace(&sbi->cp_global_sem, &lc);
 	wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
 	return 0;
 
@@ -1780,6 +1781,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+	struct f2fs_lock_context lc;
 	unsigned long long ckpt_ver;
 	int err = 0;
 
@@ -1794,7 +1796,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 		f2fs_warn(sbi, "Start checkpoint disabled!");
 	}
 	if (cpc->reason != CP_RESIZE)
-		f2fs_down_write(&sbi->cp_global_sem);
+		f2fs_down_write_trace(&sbi->cp_global_sem, &lc);
 
 	stat_cp_time(cpc, CP_TIME_LOCK);
 
@@ -1884,7 +1886,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, CP_PHASE_FINISH_CHECKPOINT);
 out:
 	if (cpc->reason != CP_RESIZE)
-		f2fs_up_write(&sbi->cp_global_sem);
+		f2fs_up_write_trace(&sbi->cp_global_sem, &lc);
 	return err;
 }
 
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5b6e632b37a9..baaae854c74f 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -179,6 +179,7 @@ enum f2fs_lock_name {
 	LOCK_NAME_NODE_CHANGE,
 	LOCK_NAME_NODE_WRITE,
 	LOCK_NAME_GC_LOCK,
+	LOCK_NAME_CP_GLOBAL,
 };
 
 /*
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 391e66064c7e..1538f5b0a644 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -2267,6 +2267,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
 	struct f2fs_lock_context lc;
 	struct f2fs_lock_context glc;
+	struct f2fs_lock_context clc;
 	unsigned int secs;
 	int err = 0;
 	__u32 rem;
@@ -2350,7 +2351,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 	}
 
 	f2fs_down_write_trace(&sbi->gc_lock, &glc);
-	f2fs_down_write(&sbi->cp_global_sem);
+	f2fs_down_write_trace(&sbi->cp_global_sem, &clc);
 
 	spin_lock(&sbi->stat_lock);
 	if (shrunk_blocks + valid_user_blocks(sbi) +
@@ -2398,7 +2399,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
 		spin_unlock(&sbi->stat_lock);
 	}
 out_err:
-	f2fs_up_write(&sbi->cp_global_sem);
+	f2fs_up_write_trace(&sbi->cp_global_sem, &clc);
 	f2fs_up_write_trace(&sbi->gc_lock, &glc);
 	thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
 	return err;
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index c3415ebb9f50..39f6e9830a9c 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -875,6 +875,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
 	LIST_HEAD(inode_list);
 	LIST_HEAD(tmp_inode_list);
 	LIST_HEAD(dir_list);
+	struct f2fs_lock_context lc;
 	int err;
 	int ret = 0;
 	unsigned long s_flags = sbi->sb->s_flags;
@@ -888,7 +889,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
 		f2fs_info(sbi, "recover fsync data on readonly fs");
 
 	/* prevent checkpoint */
-	f2fs_down_write(&sbi->cp_global_sem);
+	f2fs_down_write_trace(&sbi->cp_global_sem, &lc);
 
 	/* step #1: find fsynced inode numbers */
 	err = find_fsync_dnodes(sbi, &inode_list, check_only, &new_inode);
@@ -932,7 +933,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
 	if (!err)
 		clear_sbi_flag(sbi, SBI_POR_DOING);
 
-	f2fs_up_write(&sbi->cp_global_sem);
+	f2fs_up_write_trace(&sbi->cp_global_sem, &lc);
 
 	/* let's drop all the directory inodes for clean checkpoint */
 	destroy_fsync_dnodes(&dir_list, err);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index abb468eb4394..3583a640e614 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4898,7 +4898,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	/* initialize locks within allocated memory */
 	init_f2fs_rwsem_trace(&sbi->gc_lock, sbi, LOCK_NAME_GC_LOCK);
 	mutex_init(&sbi->writepages);
-	init_f2fs_rwsem(&sbi->cp_global_sem);
+	init_f2fs_rwsem_trace(&sbi->cp_global_sem, sbi, LOCK_NAME_CP_GLOBAL);
 	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
 	init_f2fs_rwsem_trace(&sbi->node_change, sbi, LOCK_NAME_NODE_CHANGE);
 	spin_lock_init(&sbi->stat_lock);
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index bf353e7e024d..859de7c8d1c7 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -189,7 +189,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
 		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
 		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
-		{ LOCK_NAME_GC_LOCK,		"gc_lock" })
+		{ LOCK_NAME_GC_LOCK,		"gc_lock" },		\
+		{ LOCK_NAME_CP_GLOBAL,		"cp_global" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 08/14] f2fs: trace elapsed time for io_rwsem lock
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (5 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 07/14] f2fs: trace elapsed time for cp_global_sem lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 09/14] f2fs: clean up w/ __f2fs_schedule_timeout() Chao Yu
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Use f2fs_{down,up}_{read,write}_trace for io_rwsem to trace lock elapsed time.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/data.c              | 18 +++++++++++-------
 fs/f2fs/f2fs.h              |  1 +
 include/trace/events/f2fs.h |  3 ++-
 3 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 79455d7acba5..7dee58fbfc0b 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -620,7 +620,8 @@ int f2fs_init_write_merge_io(struct f2fs_sb_info *sbi)
 		for (j = HOT; j < n; j++) {
 			struct f2fs_bio_info *io = &sbi->write_io[i][j];
 
-			init_f2fs_rwsem(&io->io_rwsem);
+			init_f2fs_rwsem_trace(&io->io_rwsem, sbi,
+						LOCK_NAME_IO_RWSEM);
 			io->sbi = sbi;
 			io->bio = NULL;
 			io->last_block_in_bio = 0;
@@ -644,8 +645,9 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
 {
 	enum page_type btype = PAGE_TYPE_OF_BIO(type);
 	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
+	struct f2fs_lock_context lc;
 
-	f2fs_down_write(&io->io_rwsem);
+	f2fs_down_write_trace(&io->io_rwsem, &lc);
 
 	if (!io->bio)
 		goto unlock_out;
@@ -659,7 +661,7 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
 	}
 	__submit_merged_bio(io);
 unlock_out:
-	f2fs_up_write(&io->io_rwsem);
+	f2fs_up_write_trace(&io->io_rwsem, &lc);
 }
 
 static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
@@ -674,10 +676,11 @@ static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
 		if (!force)	{
 			enum page_type btype = PAGE_TYPE_OF_BIO(type);
 			struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
+			struct f2fs_lock_context lc;
 
-			f2fs_down_read(&io->io_rwsem);
+			f2fs_down_read_trace(&io->io_rwsem, &lc);
 			ret = __has_merged_page(io->bio, inode, folio, ino);
-			f2fs_up_read(&io->io_rwsem);
+			f2fs_up_read_trace(&io->io_rwsem, &lc);
 		}
 		if (ret) {
 			__f2fs_submit_merged_write(sbi, type, temp);
@@ -987,11 +990,12 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
 	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
 	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
 	struct folio *bio_folio;
+	struct f2fs_lock_context lc;
 	enum count_type type;
 
 	f2fs_bug_on(sbi, is_read_io(fio->op));
 
-	f2fs_down_write(&io->io_rwsem);
+	f2fs_down_write_trace(&io->io_rwsem, &lc);
 next:
 #ifdef CONFIG_BLK_DEV_ZONED
 	if (f2fs_sb_has_blkzoned(sbi) && btype < META && io->zone_pending_bio) {
@@ -1073,7 +1077,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
 	if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) ||
 				!f2fs_is_checkpoint_ready(sbi))
 		__submit_merged_bio(io);
-	f2fs_up_write(&io->io_rwsem);
+	f2fs_up_write_trace(&io->io_rwsem, &lc);
 }
 
 static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index baaae854c74f..59615f590d79 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -180,6 +180,7 @@ enum f2fs_lock_name {
 	LOCK_NAME_NODE_WRITE,
 	LOCK_NAME_GC_LOCK,
 	LOCK_NAME_CP_GLOBAL,
+	LOCK_NAME_IO_RWSEM,
 };
 
 /*
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 859de7c8d1c7..c3b6b509472f 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -190,7 +190,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
 		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
 		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
 		{ LOCK_NAME_GC_LOCK,		"gc_lock" },		\
-		{ LOCK_NAME_CP_GLOBAL,		"cp_global" })
+		{ LOCK_NAME_CP_GLOBAL,		"cp_global" },		\
+		{ LOCK_NAME_IO_RWSEM,		"io_rwsem" })
 
 struct f2fs_sb_info;
 struct f2fs_io_info;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 09/14] f2fs: clean up w/ __f2fs_schedule_timeout()
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (6 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 08/14] f2fs: trace elapsed time for io_rwsem lock Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 10/14] f2fs: fix to use jiffies based precision for DEFAULT_SCHEDULE_TIMEOUT Chao Yu
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

No logic changes.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/f2fs.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 59615f590d79..cb9e94904c6b 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4988,8 +4988,7 @@ static inline void f2fs_io_schedule_timeout_killable(long timeout)
 	while (timeout) {
 		if (fatal_signal_pending(current))
 			return;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		io_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
+		__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, true);
 		if (timeout <= DEFAULT_SCHEDULE_TIMEOUT)
 			return;
 		timeout -= DEFAULT_SCHEDULE_TIMEOUT;
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 10/14] f2fs: fix to use jiffies based precision for DEFAULT_SCHEDULE_TIMEOUT
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (7 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 09/14] f2fs: clean up w/ __f2fs_schedule_timeout() Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 11/14] f2fs: fix timeout precision of f2fs_io_schedule_timeout_killable() Chao Yu
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Due to timeout parameter in {io,}_schedule_timeout() is based on jiffies
unit precision. It will lose precision when using msecs_to_jiffies(x)
for conversion.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/f2fs.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index cb9e94904c6b..c4d3b37821d6 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -681,8 +681,8 @@ enum {
 
 #define DEFAULT_RETRY_IO_COUNT	8	/* maximum retry read IO or flush count */
 
-/* IO/non-IO congestion wait timeout value, default: 1ms */
-#define	DEFAULT_SCHEDULE_TIMEOUT	(msecs_to_jiffies(1))
+/* IO/non-IO congestion wait timeout value, default: 1 jiffies */
+#define	DEFAULT_SCHEDULE_TIMEOUT	1
 
 /* timeout value injected, default: 1000ms */
 #define DEFAULT_FAULT_TIMEOUT	(msecs_to_jiffies(1000))
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 11/14] f2fs: fix timeout precision of f2fs_io_schedule_timeout_killable()
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (8 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 10/14] f2fs: fix to use jiffies based precision for DEFAULT_SCHEDULE_TIMEOUT Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 12/14] f2fs: rename FAULT_TIMEOUT to FAULT_ATOMIC_TIMEOUT Chao Yu
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

Sometimes, f2fs_io_schedule_timeout_killable(HZ) may delay for about 2
seconds, this is because __f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT)
may delay for about 2 * DEFAULT_SCHEDULE_TIMEOUT due to its precision, but
we only account the delay as DEFAULT_SCHEDULE_TIMEOUT as below, fix it.

f2fs_io_schedule_timeout_killable()
..
	timeout -= DEFAULT_SCHEDULE_TIMEOUT;

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/f2fs.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c4d3b37821d6..54cde9a0e24c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4985,13 +4985,12 @@ static inline void __f2fs_schedule_timeout(long timeout, bool io)
 
 static inline void f2fs_io_schedule_timeout_killable(long timeout)
 {
-	while (timeout) {
+	unsigned long last_time = jiffies + timeout;
+
+	while (jiffies < last_time) {
 		if (fatal_signal_pending(current))
 			return;
 		__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, true);
-		if (timeout <= DEFAULT_SCHEDULE_TIMEOUT)
-			return;
-		timeout -= DEFAULT_SCHEDULE_TIMEOUT;
 	}
 }
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 12/14] f2fs: rename FAULT_TIMEOUT to FAULT_ATOMIC_TIMEOUT
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (9 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 11/14] f2fs: fix timeout precision of f2fs_io_schedule_timeout_killable() Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 13/14] f2fs: introduce FAULT_LOCK_TIMEOUT Chao Yu
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

No logic changes.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 2 +-
 Documentation/filesystems/f2fs.rst      | 2 +-
 fs/f2fs/f2fs.h                          | 2 +-
 fs/f2fs/segment.c                       | 2 +-
 fs/f2fs/super.c                         | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index 648ddd0d59f6..de5a80124e04 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -741,7 +741,7 @@ Description:	Support configuring fault injection type, should be
 		FAULT_BLKADDR_CONSISTENCE        0x00080000
 		FAULT_NO_SEGMENT                 0x00100000
 		FAULT_INCONSISTENT_FOOTER        0x00200000
-		FAULT_TIMEOUT                    0x00400000 (1000ms)
+		FAULT_ATOMIC_TIMEOUT             0x00400000 (1000ms)
 		FAULT_VMALLOC                    0x00800000
 		===========================      ==========
 
diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
index 9b3b835a174e..2d71efa7db7a 100644
--- a/Documentation/filesystems/f2fs.rst
+++ b/Documentation/filesystems/f2fs.rst
@@ -215,7 +215,7 @@ fault_type=%d		 Support configuring fault injection type, should be
 			     FAULT_BLKADDR_CONSISTENCE        0x00080000
 			     FAULT_NO_SEGMENT                 0x00100000
 			     FAULT_INCONSISTENT_FOOTER        0x00200000
-			     FAULT_TIMEOUT                    0x00400000 (1000ms)
+			     FAULT_ATOMIC_TIMEOUT             0x00400000 (1000ms)
 			     FAULT_VMALLOC                    0x00800000
 			     ===========================      ==========
 mode=%s			 Control block allocation mode which supports "adaptive"
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 54cde9a0e24c..8c0ce9fd954f 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -63,7 +63,7 @@ enum {
 	FAULT_BLKADDR_CONSISTENCE,
 	FAULT_NO_SEGMENT,
 	FAULT_INCONSISTENT_FOOTER,
-	FAULT_TIMEOUT,
+	FAULT_ATOMIC_TIMEOUT,
 	FAULT_VMALLOC,
 	FAULT_MAX,
 };
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 776b0df828ed..469d37c37398 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -371,7 +371,7 @@ static int __f2fs_commit_atomic_write(struct inode *inode)
 	}
 
 out:
-	if (time_to_inject(sbi, FAULT_TIMEOUT))
+	if (time_to_inject(sbi, FAULT_ATOMIC_TIMEOUT))
 		f2fs_io_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT);
 
 	if (ret) {
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 3583a640e614..9e41fe39dbf6 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -67,7 +67,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
 	[FAULT_BLKADDR_CONSISTENCE]	= "inconsistent blkaddr",
 	[FAULT_NO_SEGMENT]		= "no free segment",
 	[FAULT_INCONSISTENT_FOOTER]	= "inconsistent footer",
-	[FAULT_TIMEOUT]			= "timeout",
+	[FAULT_ATOMIC_TIMEOUT]		= "atomic timeout",
 	[FAULT_VMALLOC]			= "vmalloc",
 };
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 13/14] f2fs: introduce FAULT_LOCK_TIMEOUT
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (10 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 12/14] f2fs: rename FAULT_TIMEOUT to FAULT_ATOMIC_TIMEOUT Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  2:07 ` [PATCH 14/14] f2fs: sysfs: introduce inject_lock_timeout Chao Yu
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

This patch introduce a new fault type FAULT_LOCK_TIMEOUT, it can
be used to inject timeout into lock duration.

Timeout type can be set via /sys/fs/f2fs/<disk>/inject_timeout_type

Signed-off-by: Chao Yu <chao@kernel.org>
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 1 +
 Documentation/filesystems/f2fs.rst      | 1 +
 fs/f2fs/checkpoint.c                    | 3 +++
 fs/f2fs/f2fs.h                          | 1 +
 fs/f2fs/super.c                         | 1 +
 5 files changed, 7 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index de5a80124e04..4b0bec3c0746 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -743,6 +743,7 @@ Description:	Support configuring fault injection type, should be
 		FAULT_INCONSISTENT_FOOTER        0x00200000
 		FAULT_ATOMIC_TIMEOUT             0x00400000 (1000ms)
 		FAULT_VMALLOC                    0x00800000
+		FAULT_LOCK_TIMEOUT               0x01000000 (1000ms)
 		===========================      ==========
 
 What:		/sys/fs/f2fs/<disk>/discard_io_aware_gran
diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
index 2d71efa7db7a..33d2166ac6b7 100644
--- a/Documentation/filesystems/f2fs.rst
+++ b/Documentation/filesystems/f2fs.rst
@@ -217,6 +217,7 @@ fault_type=%d		 Support configuring fault injection type, should be
 			     FAULT_INCONSISTENT_FOOTER        0x00200000
 			     FAULT_ATOMIC_TIMEOUT             0x00400000 (1000ms)
 			     FAULT_VMALLOC                    0x00800000
+			     FAULT_LOCK_TIMEOUT               0x01000000 (1000ms)
 			     ===========================      ==========
 mode=%s			 Control block allocation mode which supports "adaptive"
 			 and "lfs". In "lfs" mode, there should be no random
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 86656231ce83..f2ab5ba8fb6a 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -63,6 +63,9 @@ static inline void trace_lock_elapsed_time_end(struct f2fs_rwsem *sem,
 	if (!lc->lock_trace)
 		return;
 
+	if (time_to_inject(sem->sbi, FAULT_LOCK_TIMEOUT))
+		f2fs_io_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT);
+
 	get_lock_elapsed_time(&tts);
 
 	total_time = div_u64(tts.total_time - lc->ts.total_time, npm);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 8c0ce9fd954f..4f8eb1292ebf 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -65,6 +65,7 @@ enum {
 	FAULT_INCONSISTENT_FOOTER,
 	FAULT_ATOMIC_TIMEOUT,
 	FAULT_VMALLOC,
+	FAULT_LOCK_TIMEOUT,
 	FAULT_MAX,
 };
 
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 9e41fe39dbf6..1915d194153e 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -69,6 +69,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
 	[FAULT_INCONSISTENT_FOOTER]	= "inconsistent footer",
 	[FAULT_ATOMIC_TIMEOUT]		= "atomic timeout",
 	[FAULT_VMALLOC]			= "vmalloc",
+	[FAULT_LOCK_TIMEOUT]		= "lock timeout",
 };
 
 int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 14/14] f2fs: sysfs: introduce inject_lock_timeout
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (11 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 13/14] f2fs: introduce FAULT_LOCK_TIMEOUT Chao Yu
@ 2026-01-04  2:07 ` Chao Yu
  2026-01-04  5:28 ` [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Jaegeuk Kim
  2026-01-07  3:30 ` [f2fs-dev] " patchwork-bot+f2fs
  14 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  2:07 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, Chao Yu

This patch adds a new sysfs node in /sys/fs/f2fs/<disk>/inject_lock_timeout,
it relies on CONFIG_F2FS_FAULT_INJECTION kernel config.

It can be used to simulate different type of timeout in lock duration.

==========     ===============================
Flag_Value     Flag_Description
==========     ===============================
0x00000000     No timeout (default)
0x00000001     Simulate running time
0x00000002     Simulate IO type sleep time
0x00000003     Simulate Non-IO type sleep time
0x00000004     Simulate runnable time
==========     ===============================

Signed-off-by: Chao Yu <chao@kernel.org>
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 14 +++++++
 fs/f2fs/checkpoint.c                    |  2 +-
 fs/f2fs/f2fs.h                          | 22 +++++++++--
 fs/f2fs/segment.c                       |  2 +-
 fs/f2fs/super.c                         | 49 +++++++++++++++++++++++++
 fs/f2fs/sysfs.c                         |  9 +++++
 6 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index 4b0bec3c0746..ca9ed3b44b31 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -948,3 +948,17 @@ Description:	This is a threshold, once a thread enters critical region that lock
 		elapsed time exceeds this threshold, f2fs will print tracepoint to dump information
 		of related context. This sysfs entry can be used to control the value of threshold,
 		by default, the value is 500 ms.
+
+What:		/sys/fs/f2fs/<disk>/inject_timeout_type
+Date:		December 2025
+Contact:	"Chao Yu" <chao@kernel.org>
+Description:	This sysfs entry can be used to change type of injected timeout:
+		==========     ===============================
+		Flag_Value     Flag_Description
+		==========     ===============================
+		0x00000000     No timeout (default)
+		0x00000001     Simulate running time
+		0x00000002     Simulate IO type sleep time
+		0x00000003     Simulate Non-IO type sleep time
+		0x00000004     Simulate runnable time
+		==========     ===============================
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index f2ab5ba8fb6a..3dfc83a0813e 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -64,7 +64,7 @@ static inline void trace_lock_elapsed_time_end(struct f2fs_rwsem *sem,
 		return;
 
 	if (time_to_inject(sem->sbi, FAULT_LOCK_TIMEOUT))
-		f2fs_io_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT);
+		f2fs_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT, true);
 
 	get_lock_elapsed_time(&tts);
 
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 4f8eb1292ebf..ded41b416ed7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -73,7 +73,8 @@ enum {
 enum fault_option {
 	FAULT_RATE	= 1,	/* only update fault rate */
 	FAULT_TYPE	= 2,	/* only update fault type */
-	FAULT_ALL	= 4,	/* reset all fault injection options/stats */
+	FAULT_TIMEOUT	= 4,	/* only update fault timeout type */
+	FAULT_ALL	= 8,	/* reset all fault injection options/stats */
 };
 
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -83,6 +84,7 @@ struct f2fs_fault_info {
 	unsigned int inject_type;
 	/* Used to account total count of injection for each type */
 	unsigned int inject_count[FAULT_MAX];
+	unsigned int inject_lock_timeout;	/* inject lock timeout */
 };
 
 extern const char *f2fs_fault_name[FAULT_MAX];
@@ -184,6 +186,15 @@ enum f2fs_lock_name {
 	LOCK_NAME_IO_RWSEM,
 };
 
+enum f2fs_timeout_type {
+	TIMEOUT_TYPE_NONE,
+	TIMEOUT_TYPE_RUNNING,
+	TIMEOUT_TYPE_IO_SLEEP,
+	TIMEOUT_TYPE_NONIO_SLEEP,
+	TIMEOUT_TYPE_RUNNABLE,
+	TIMEOUT_TYPE_MAX,
+};
+
 /*
  * An implementation of an rwsem that is explicitly unfair to readers. This
  * prevents priority inversion when a low-priority reader acquires the read lock
@@ -4927,6 +4938,7 @@ static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx)
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 extern int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
 					unsigned long type, enum fault_option fo);
+extern void f2fs_simulate_lock_timeout(struct f2fs_sb_info *sbi);
 #else
 static inline int f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
 					unsigned long rate, unsigned long type,
@@ -4934,6 +4946,10 @@ static inline int f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
 {
 	return 0;
 }
+static inline void f2fs_simulate_lock_timeout(struct f2fs_sb_info *sbi)
+{
+	return;
+}
 #endif
 
 static inline bool is_journalled_quota(struct f2fs_sb_info *sbi)
@@ -4984,14 +5000,14 @@ static inline void __f2fs_schedule_timeout(long timeout, bool io)
 #define f2fs_schedule_timeout(timeout)			\
 			__f2fs_schedule_timeout(timeout, false)
 
-static inline void f2fs_io_schedule_timeout_killable(long timeout)
+static inline void f2fs_schedule_timeout_killable(long timeout, bool io)
 {
 	unsigned long last_time = jiffies + timeout;
 
 	while (jiffies < last_time) {
 		if (fatal_signal_pending(current))
 			return;
-		__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, true);
+		__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, io);
 	}
 }
 
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 469d37c37398..587ae3b4bfd8 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -372,7 +372,7 @@ static int __f2fs_commit_atomic_write(struct inode *inode)
 
 out:
 	if (time_to_inject(sbi, FAULT_ATOMIC_TIMEOUT))
-		f2fs_io_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT);
+		f2fs_schedule_timeout_killable(DEFAULT_FAULT_TIMEOUT, true);
 
 	if (ret) {
 		sbi->revoked_atomic_block += fi->atomic_write_cnt;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 1915d194153e..fe6a6d96e7ea 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -97,8 +97,57 @@ int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
 		f2fs_info(sbi, "build fault injection type: 0x%lx", type);
 	}
 
+	if (fo & FAULT_TIMEOUT) {
+		if (type >= TIMEOUT_TYPE_MAX)
+			return -EINVAL;
+		ffi->inject_lock_timeout = (unsigned int)type;
+		f2fs_info(sbi, "build fault timeout injection type: 0x%lx", type);
+	}
+
 	return 0;
 }
+
+static void inject_timeout(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
+	enum f2fs_timeout_type type = ffi->inject_lock_timeout;
+	unsigned long start_time = jiffies;
+	unsigned long timeout = HZ;
+
+	switch (type) {
+	case TIMEOUT_TYPE_RUNNING:
+		while (!time_after(jiffies, start_time + timeout)) {
+			if (fatal_signal_pending(current))
+				return;
+			;
+		}
+		break;
+	case TIMEOUT_TYPE_IO_SLEEP:
+		f2fs_schedule_timeout_killable(timeout, true);
+		break;
+	case TIMEOUT_TYPE_NONIO_SLEEP:
+		f2fs_schedule_timeout_killable(timeout, false);
+		break;
+	case TIMEOUT_TYPE_RUNNABLE:
+		while (!time_after(jiffies, start_time + timeout)) {
+			if (fatal_signal_pending(current))
+				return;
+			schedule();
+		}
+		break;
+	default:
+		return;
+	}
+}
+
+void f2fs_simulate_lock_timeout(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_lock_context lc;
+
+	f2fs_lock_op(sbi, &lc);
+	inject_timeout(sbi);
+	f2fs_unlock_op(sbi, &lc);
+}
 #endif
 
 /* f2fs-wide shrinker description */
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index e95aa23c5bef..91bc0544ba1f 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -35,6 +35,7 @@ enum {
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	FAULT_INFO_RATE,	/* struct f2fs_fault_info */
 	FAULT_INFO_TYPE,	/* struct f2fs_fault_info */
+	FAULT_INFO_TIMEOUT,	/* struct f2fs_fault_info */
 #endif
 	RESERVED_BLOCKS,	/* struct f2fs_sb_info */
 	CPRC_INFO,	/* struct ckpt_req_control */
@@ -570,6 +571,12 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
 			return -EINVAL;
 		return count;
 	}
+	if (a->struct_type == FAULT_INFO_TIMEOUT) {
+		if (f2fs_build_fault_attr(sbi, 0, t, FAULT_TIMEOUT))
+			return -EINVAL;
+		f2fs_simulate_lock_timeout(sbi);
+		return count;
+	}
 #endif
 	if (a->struct_type == RESERVED_BLOCKS) {
 		spin_lock(&sbi->stat_lock);
@@ -1277,6 +1284,7 @@ STAT_INFO_RO_ATTR(gc_background_calls, gc_call_count[BACKGROUND]);
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_RATE, inject_rate);
 FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_TYPE, inject_type);
+FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_TIMEOUT, inject_lock_timeout);
 #endif
 
 /* RESERVED_BLOCKS ATTR */
@@ -1406,6 +1414,7 @@ static struct attribute *f2fs_attrs[] = {
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 	ATTR_LIST(inject_rate),
 	ATTR_LIST(inject_type),
+	ATTR_LIST(inject_lock_timeout),
 #endif
 	ATTR_LIST(data_io_flag),
 	ATTR_LIST(node_io_flag),
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (12 preceding siblings ...)
  2026-01-04  2:07 ` [PATCH 14/14] f2fs: sysfs: introduce inject_lock_timeout Chao Yu
@ 2026-01-04  5:28 ` Jaegeuk Kim
  2026-01-07  3:30 ` [f2fs-dev] " patchwork-bot+f2fs
  14 siblings, 0 replies; 19+ messages in thread
From: Jaegeuk Kim @ 2026-01-04  5:28 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel

Stuck when disabling checkpoint:

[  403.438233][  T739]  __switch_to+0x164/0x324
[  403.442532][  T739]  __schedule+0xbd0/0x1d28
[  403.446822][  T739]  schedule+0x4c/0x118
[  403.450758][  T739]  schedule_preempt_disabled+0x24/0x44
[  403.456083][  T739]  rwsem_down_write_slowpath+0x438/0x988
[  403.461588][  T739]  down_write+0x10c/0x16c
[  403.465785][  T739]  f2fs_down_write_trace+0x1c/0x70
[  403.470797][  T739]  f2fs_disable_checkpoint+0x114/0x2b8
[  403.476126][  T739]  f2fs_fill_super+0x22c8/0x2728
[  403.480924][  T739]  get_tree_bdev_flags+0x144/0x1dc
[  403.485894][  T739]  get_tree_bdev+0x14/0x24
[  403.490176][  T739]  f2fs_get_tree+0x18/0x28
[  403.494448][  T739]  vfs_get_tree+0x48/0x10c
[  403.498724][  T739]  path_mount+0x62c/0xb74

On 01/04, Chao Yu wrote:
> This patch adds lock elapsed time trace facility for f2fs rwsemphore.
> 
> If total elapsed time of critical region covered by lock exceeds a
> threshold, it will print tracepoint to dump information of lock related
> context, including:
> - thread information
> - CPU/IO priority
> - lock information
> - elapsed time
>  - total time
>  - running time (depend on CONFIG_64BIT)
>  - runnable time (depend on CONFIG_SCHED_INFO and CONFIG_SCHEDSTATS)
>  - io sleep time (depend on CONFIG_TASK_DELAY_ACCT and
> 		  /proc/sys/kernel/task_delayacct)
>  - other time    (by default other time will account nonio sleep time,
>                   but, if above kconfig is not defined, other time will
>                   include runnable time and/or io sleep time as wll)
> 
> output:
>     f2fs_lock_elapsed_time: dev = (254,52), comm: sh, pid: 13855, prio: 120, ioprio_class: 2, ioprio_data: 4, lock_name: cp_rwsem, lock_type: rlock, total: 1000, running: 993, runnable: 2, io_sleep: 0, other: 5
> 
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
>  fs/f2fs/checkpoint.c        | 106 ++++++++++++++++++++++++++++++++++++
>  fs/f2fs/f2fs.h              |  51 +++++++++++++++--
>  include/trace/events/f2fs.h |  68 +++++++++++++++++++++++
>  3 files changed, 221 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index 300664269eb6..bc6058a3122b 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -14,6 +14,9 @@
>  #include <linux/pagevec.h>
>  #include <linux/swap.h>
>  #include <linux/kthread.h>
> +#include <linux/delayacct.h>
> +#include <linux/ioprio.h>
> +#include <linux/math64.h>
>  
>  #include "f2fs.h"
>  #include "node.h"
> @@ -21,6 +24,109 @@
>  #include "iostat.h"
>  #include <trace/events/f2fs.h>
>  
> +static inline void get_lock_elapsed_time(struct f2fs_time_stat *ts)
> +{
> +	ts->total_time = ktime_get();
> +#ifdef CONFIG_64BIT
> +	ts->running_time = current->se.sum_exec_runtime;
> +#endif
> +#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
> +	ts->runnable_time = current->sched_info.run_delay;
> +#endif
> +#ifdef CONFIG_TASK_DELAY_ACCT
> +	if (current->delays)
> +		ts->io_sleep_time = current->delays->blkio_delay;
> +#endif
> +}
> +
> +static inline void trace_lock_elapsed_time_start(struct f2fs_rwsem *sem,
> +						struct f2fs_lock_context *lc)
> +{
> +	lc->lock_trace = trace_f2fs_lock_elapsed_time_enabled();
> +	if (!lc->lock_trace)
> +		return;
> +
> +	get_lock_elapsed_time(&lc->ts);
> +}
> +
> +static inline void trace_lock_elapsed_time_end(struct f2fs_rwsem *sem,
> +				struct f2fs_lock_context *lc, bool is_write)
> +{
> +	struct f2fs_time_stat tts;
> +	unsigned long long total_time;
> +	unsigned long long running_time = 0;
> +	unsigned long long runnable_time = 0;
> +	unsigned long long io_sleep_time = 0;
> +	unsigned long long other_time = 0;
> +	unsigned npm = NSEC_PER_MSEC;
> +
> +	if (!lc->lock_trace)
> +		return;
> +
> +	get_lock_elapsed_time(&tts);
> +
> +	total_time = div_u64(tts.total_time - lc->ts.total_time, npm);
> +	if (total_time <= MAX_LOCK_ELAPSED_TIME)
> +		return;
> +
> +#ifdef CONFIG_64BIT
> +	running_time = div_u64(tts.running_time - lc->ts.running_time, npm);
> +#endif
> +#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
> +	runnable_time = div_u64(tts.runnable_time - lc->ts.runnable_time, npm);
> +#endif
> +#ifdef CONFIG_TASK_DELAY_ACCT
> +	io_sleep_time = div_u64(tts.io_sleep_time - lc->ts.io_sleep_time, npm);
> +#endif
> +	if (total_time > running_time + io_sleep_time + runnable_time)
> +		other_time = total_time - running_time -
> +				io_sleep_time - runnable_time;
> +
> +	trace_f2fs_lock_elapsed_time(sem->sbi, sem->name, is_write, current,
> +			get_current_ioprio(), total_time, running_time,
> +			runnable_time, io_sleep_time, other_time);
> +}
> +
> +void f2fs_down_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	f2fs_down_read(sem);
> +	trace_lock_elapsed_time_start(sem, lc);
> +}
> +
> +int f2fs_down_read_trylock_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	if (!f2fs_down_read_trylock(sem))
> +		return 0;
> +	trace_lock_elapsed_time_start(sem, lc);
> +	return 1;
> +}
> +
> +void f2fs_up_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	f2fs_up_read(sem);
> +	trace_lock_elapsed_time_end(sem, lc, false);
> +}
> +
> +void f2fs_down_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	f2fs_down_write(sem);
> +	trace_lock_elapsed_time_start(sem, lc);
> +}
> +
> +int f2fs_down_write_trylock_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	if (!f2fs_down_write_trylock(sem))
> +		return 0;
> +	trace_lock_elapsed_time_start(sem, lc);
> +	return 1;
> +}
> +
> +void f2fs_up_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc)
> +{
> +	f2fs_up_write(sem);
> +	trace_lock_elapsed_time_end(sem, lc, true);
> +}
> +
>  #define DEFAULT_CHECKPOINT_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 3))
>  
>  static struct kmem_cache *ino_entry_slab;
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index c3e1611fce18..7e22315dbedd 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -173,6 +173,10 @@ enum device_allocation_policy {
>  	ALLOCATE_FORWARD_FROM_HINT,
>  };
>  
> +enum f2fs_lock_name {
> +	LOCK_NAME_NONE,
> +};
> +
>  /*
>   * An implementation of an rwsem that is explicitly unfair to readers. This
>   * prevents priority inversion when a low-priority reader acquires the read lock
> @@ -181,6 +185,8 @@ enum device_allocation_policy {
>   */
>  
>  struct f2fs_rwsem {
> +	struct f2fs_sb_info *sbi;
> +	enum f2fs_lock_name name;
>          struct rw_semaphore internal_rwsem;
>  #ifdef CONFIG_F2FS_UNFAIR_RWSEM
>          wait_queue_head_t read_waiters;
> @@ -1409,6 +1415,24 @@ struct f2fs_gc_control {
>  	unsigned int nr_free_secs;	/* # of free sections to do GC */
>  };
>  
> +struct f2fs_time_stat {
> +	unsigned long long total_time;		/* total wall clock time */
> +#ifdef CONFIG_64BIT
> +	unsigned long long running_time;	/* running time */
> +#endif
> +#if defined(CONFIG_SCHED_INFO) && defined(CONFIG_SCHEDSTATS)
> +	unsigned long long runnable_time;	/* runnable(including preempted) time */
> +#endif
> +#ifdef CONFIG_TASK_DELAY_ACCT
> +	unsigned long long io_sleep_time;	/* IO sleep time */
> +#endif
> +};
> +
> +struct f2fs_lock_context {
> +	struct f2fs_time_stat ts;
> +	bool lock_trace;
> +};
> +
>  /*
>   * For s_flag in struct f2fs_sb_info
>   * Modification on enum should be synchronized with s_flag array
> @@ -1525,6 +1549,9 @@ enum f2fs_lookup_mode {
>  	LOOKUP_AUTO,
>  };
>  
> +/* a threshold of maximum elapsed time in critical region to print tracepoint */
> +#define MAX_LOCK_ELAPSED_TIME		500
> +
>  static inline int f2fs_test_bit(unsigned int nr, char *addr);
>  static inline void f2fs_set_bit(unsigned int nr, char *addr);
>  static inline void f2fs_clear_bit(unsigned int nr, char *addr);
> @@ -2263,16 +2290,22 @@ static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
>  	spin_unlock_irqrestore(&sbi->cp_lock, flags);
>  }
>  
> -#define init_f2fs_rwsem(sem)					\
> +#define init_f2fs_rwsem(sem)	__init_f2fs_rwsem(sem, NULL, LOCK_NAME_NONE)
> +#define init_f2fs_rwsem_trace	__init_f2fs_rwsem
> +
> +#define __init_f2fs_rwsem(sem, sbi, name)			\
>  do {								\
>  	static struct lock_class_key __key;			\
>  								\
> -	__init_f2fs_rwsem((sem), #sem, &__key);			\
> +	do_init_f2fs_rwsem((sem), #sem, &__key, sbi, name);	\
>  } while (0)
>  
> -static inline void __init_f2fs_rwsem(struct f2fs_rwsem *sem,
> -		const char *sem_name, struct lock_class_key *key)
> +static inline void do_init_f2fs_rwsem(struct f2fs_rwsem *sem,
> +		const char *sem_name, struct lock_class_key *key,
> +		struct f2fs_sb_info *sbi, enum f2fs_lock_name name)
>  {
> +	sem->sbi = sbi;
> +	sem->name = name;
>  	__init_rwsem(&sem->internal_rwsem, sem_name, key);
>  #ifdef CONFIG_F2FS_UNFAIR_RWSEM
>  	init_waitqueue_head(&sem->read_waiters);
> @@ -2341,6 +2374,16 @@ static inline void f2fs_up_write(struct f2fs_rwsem *sem)
>  #endif
>  }
>  
> +void f2fs_down_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
> +int f2fs_down_read_trylock_trace(struct f2fs_rwsem *sem,
> +						struct f2fs_lock_context *lc);
> +void f2fs_up_read_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
> +void f2fs_down_write_trace(struct f2fs_rwsem *sem,
> +						struct f2fs_lock_context *lc);
> +int f2fs_down_write_trylock_trace(struct f2fs_rwsem *sem,
> +						struct f2fs_lock_context *lc);
> +void f2fs_up_write_trace(struct f2fs_rwsem *sem, struct f2fs_lock_context *lc);
> +
>  static inline void disable_nat_bits(struct f2fs_sb_info *sbi, bool lock)
>  {
>  	unsigned long flags;
> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> index 635dcabcf1c7..9a852a16df9c 100644
> --- a/include/trace/events/f2fs.h
> +++ b/include/trace/events/f2fs.h
> @@ -184,6 +184,10 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
>  		{ CP_PHASE_FINISH_BLOCK_OPS,	"finish block_ops" },			\
>  		{ CP_PHASE_FINISH_CHECKPOINT,	"finish checkpoint" })
>  
> +#define show_lock_name(lock)						\
> +	__print_symbolic(lock,						\
> +		{ LOCK_NAME_NONE,		"none" })
> +
>  struct f2fs_sb_info;
>  struct f2fs_io_info;
>  struct extent_info;
> @@ -2452,6 +2456,70 @@ DEFINE_EVENT(f2fs__rw_end, f2fs_datawrite_end,
>  	TP_ARGS(inode, offset, bytes)
>  );
>  
> +TRACE_EVENT(f2fs_lock_elapsed_time,
> +
> +	TP_PROTO(struct f2fs_sb_info *sbi, enum f2fs_lock_name lock_name,
> +		bool is_write, struct task_struct *p, int ioprio,
> +		unsigned long long total_time,
> +		unsigned long long running_time,
> +		unsigned long long runnable_time,
> +		unsigned long long io_sleep_time,
> +		unsigned long long other_time),
> +
> +	TP_ARGS(sbi, lock_name, is_write, p, ioprio, total_time, running_time,
> +		runnable_time, io_sleep_time, other_time),
> +
> +	TP_STRUCT__entry(
> +		__field(dev_t, dev)
> +		__array(char, comm, TASK_COMM_LEN)
> +		__field(pid_t, pid)
> +		__field(int, prio)
> +		__field(int, ioprio_class)
> +		__field(int, ioprio_data)
> +		__field(unsigned int, lock_name)
> +		__field(bool, is_write)
> +		__field(unsigned long long, total_time)
> +		__field(unsigned long long, running_time)
> +		__field(unsigned long long, runnable_time)
> +		__field(unsigned long long, io_sleep_time)
> +		__field(unsigned long long, other_time)
> +	),
> +
> +	TP_fast_assign(
> +		__entry->dev		= sbi->sb->s_dev;
> +		memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
> +		__entry->pid		= p->pid;
> +		__entry->prio		= p->prio;
> +		__entry->ioprio_class	= IOPRIO_PRIO_CLASS(ioprio);
> +		__entry->ioprio_data	= IOPRIO_PRIO_DATA(ioprio);
> +		__entry->lock_name	= lock_name;
> +		__entry->is_write	= is_write;
> +		__entry->total_time	= total_time;
> +		__entry->running_time	= running_time;
> +		__entry->runnable_time	= runnable_time;
> +		__entry->io_sleep_time	= io_sleep_time;
> +		__entry->other_time	= other_time;
> +	),
> +
> +	TP_printk("dev = (%d,%d), comm: %s, pid: %d, prio: %d, "
> +		"ioprio_class: %d, ioprio_data: %d, lock_name: %s, "
> +		"lock_type: %s, total: %llu, running: %llu, "
> +		"runnable: %llu, io_sleep: %llu, other: %llu",
> +		show_dev(__entry->dev),
> +		__entry->comm,
> +		__entry->pid,
> +		__entry->prio,
> +		__entry->ioprio_class,
> +		__entry->ioprio_data,
> +		show_lock_name(__entry->lock_name),
> +		__entry->is_write ? "wlock" : "rlock",
> +		__entry->total_time,
> +		__entry->running_time,
> +		__entry->runnable_time,
> +		__entry->io_sleep_time,
> +		__entry->other_time)
> +);
> +
>  #endif /* _TRACE_F2FS_H */
>  
>   /* This part must be outside protection */
> -- 
> 2.49.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock
  2026-01-04  2:07 ` [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock Chao Yu
@ 2026-01-04  5:35   ` Jaegeuk Kim
  2026-01-04  5:42     ` Jaegeuk Kim
  0 siblings, 1 reply; 19+ messages in thread
From: Jaegeuk Kim @ 2026-01-04  5:35 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel

On 01/04, Chao Yu wrote:
> Use f2fs_{down,up}_write_trace for gc_lock to trace lock elapsed time.
> 
> Signed-off-by: Chao Yu <chao@kernel.org>
> ---
>  fs/f2fs/checkpoint.c        | 10 ++++++----
>  fs/f2fs/f2fs.h              | 22 ++++++++++++----------
>  fs/f2fs/file.c              | 13 +++++++------
>  fs/f2fs/gc.c                | 23 +++++++++++++----------
>  fs/f2fs/segment.c           | 11 ++++++-----
>  fs/f2fs/super.c             | 15 +++++++++------
>  include/trace/events/f2fs.h |  3 ++-
>  7 files changed, 55 insertions(+), 42 deletions(-)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index dfd54cba1b35..da7bcfa2a178 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -1930,11 +1930,12 @@ void f2fs_destroy_checkpoint_caches(void)
>  static int __write_checkpoint_sync(struct f2fs_sb_info *sbi)
>  {
>  	struct cp_control cpc = { .reason = CP_SYNC, };
> +	struct f2fs_lock_context lc;
>  	int err;
>  
> -	f2fs_down_write(&sbi->gc_lock);
> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  	err = f2fs_write_checkpoint(sbi, &cpc);
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  
>  	return err;
>  }
> @@ -2022,11 +2023,12 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
>  	cpc.reason = __get_cp_reason(sbi);
>  	if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC ||
>  		sbi->umount_lock_holder == current) {
> +		struct f2fs_lock_context lc;
>  		int ret;
>  
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  		ret = f2fs_write_checkpoint(sbi, &cpc);
> -		f2fs_up_write(&sbi->gc_lock);
> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  
>  		return ret;
>  	}
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 3f6278ba620d..5b6e632b37a9 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -178,6 +178,7 @@ enum f2fs_lock_name {
>  	LOCK_NAME_CP_RWSEM,
>  	LOCK_NAME_NODE_CHANGE,
>  	LOCK_NAME_NODE_WRITE,
> +	LOCK_NAME_GC_LOCK,
>  };
>  
>  /*
> @@ -1408,16 +1409,6 @@ struct atgc_management {
>  	unsigned long long age_threshold;	/* age threshold */
>  };
>  
> -struct f2fs_gc_control {
> -	unsigned int victim_segno;	/* target victim segment number */
> -	int init_gc_type;		/* FG_GC or BG_GC */
> -	bool no_bg_gc;			/* check the space and stop bg_gc */
> -	bool should_migrate_blocks;	/* should migrate blocks */
> -	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
> -	bool one_time;			/* require one time GC in one migration unit */
> -	unsigned int nr_free_secs;	/* # of free sections to do GC */
> -};
> -
>  struct f2fs_time_stat {
>  	unsigned long long total_time;		/* total wall clock time */
>  #ifdef CONFIG_64BIT
> @@ -1436,6 +1427,17 @@ struct f2fs_lock_context {
>  	bool lock_trace;
>  };
>  
> +struct f2fs_gc_control {
> +	unsigned int victim_segno;	/* target victim segment number */
> +	int init_gc_type;		/* FG_GC or BG_GC */
> +	bool no_bg_gc;			/* check the space and stop bg_gc */
> +	bool should_migrate_blocks;	/* should migrate blocks */
> +	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
> +	bool one_time;			/* require one time GC in one migration unit */
> +	unsigned int nr_free_secs;	/* # of free sections to do GC */
> +	struct f2fs_lock_context lc;	/* lock context for gc_lock */
> +};
> +
>  /*
>   * For s_flag in struct f2fs_sb_info
>   * Modification on enum should be synchronized with s_flag array
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 1cdbbc2e1005..ce291f152bc3 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -1928,7 +1928,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
>  
>  		if (has_not_enough_free_secs(sbi, 0,
>  				sbi->reserved_pin_section)) {
> -			f2fs_down_write(&sbi->gc_lock);
> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  			stat_inc_gc_call_count(sbi, FOREGROUND);
>  			err = f2fs_gc(sbi, &gc_control);
>  			if (err && err != -ENODATA) {
> @@ -2779,12 +2779,13 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
>  		return ret;
>  
>  	if (!sync) {
> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
> +						&gc_control.lc)) {
>  			ret = -EBUSY;
>  			goto out;
>  		}
>  	} else {
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  	}
>  
>  	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
> @@ -2824,12 +2825,12 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
>  
>  do_more:
>  	if (!range->sync) {
> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
>  			ret = -EBUSY;
>  			goto out;
>  		}
>  	} else {
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  	}
>  
>  	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
> @@ -3320,7 +3321,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
>  	end_segno = min(start_segno + range.segments, dev_end_segno);
>  
>  	while (start_segno < end_segno) {
> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
>  			ret = -EBUSY;
>  			goto out;
>  		}
> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> index 8999829a9559..391e66064c7e 100644
> --- a/fs/f2fs/gc.c
> +++ b/fs/f2fs/gc.c
> @@ -102,21 +102,22 @@ static int gc_thread_func(void *data)
>  		if (sbi->gc_mode == GC_URGENT_HIGH ||
>  				sbi->gc_mode == GC_URGENT_MID) {
>  			wait_ms = gc_th->urgent_sleep_time;
> -			f2fs_down_write(&sbi->gc_lock);
> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  			goto do_gc;
>  		}
>  
>  		if (foreground) {
> -			f2fs_down_write(&sbi->gc_lock);
> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  			goto do_gc;
> -		} else if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> +		} else if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
> +							&gc_control.lc)) {
>  			stat_other_skip_bggc_count(sbi);
>  			goto next;
>  		}
>  
>  		if (!is_idle(sbi, GC_TIME)) {
>  			increase_sleep_time(gc_th, &wait_ms);
> -			f2fs_up_write(&sbi->gc_lock);
> +			f2fs_up_write_trace(&sbi->gc_lock, &gc_control.lc);
>  			stat_io_skip_bggc_count(sbi);
>  			goto next;
>  		}
> @@ -125,7 +126,8 @@ static int gc_thread_func(void *data)
>  			if (has_enough_free_blocks(sbi,
>  				gc_th->no_zoned_gc_percent)) {
>  				wait_ms = gc_th->no_gc_sleep_time;
> -				f2fs_up_write(&sbi->gc_lock);
> +				f2fs_up_write_trace(&sbi->gc_lock,
> +							&gc_control.lc);
>  				goto next;
>  			}
>  			if (wait_ms == gc_th->no_gc_sleep_time)
> @@ -2046,7 +2048,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
>  				reserved_segments(sbi),
>  				prefree_segments(sbi));
>  
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &gc_control->lc);
>  
>  	put_gc_inode(&gc_list);
>  
> @@ -2264,6 +2266,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>  	__u64 old_block_count, shrunk_blocks;
>  	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
>  	struct f2fs_lock_context lc;
> +	struct f2fs_lock_context glc;
>  	unsigned int secs;
>  	int err = 0;
>  	__u32 rem;
> @@ -2307,7 +2310,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>  	secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi));
>  
>  	/* stop other GC */
> -	if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> +	if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &glc)) {
>  		err = -EAGAIN;
>  		goto out_drop_write;
>  	}
> @@ -2329,7 +2332,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>  
>  out_unlock:
>  	f2fs_unlock_op(sbi, &lc);
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
>  out_drop_write:
>  	mnt_drop_write_file(filp);
>  	if (err)
> @@ -2346,7 +2349,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>  		return -EROFS;
>  	}
>  
> -	f2fs_down_write(&sbi->gc_lock);
> +	f2fs_down_write_trace(&sbi->gc_lock, &glc);
>  	f2fs_down_write(&sbi->cp_global_sem);
>  
>  	spin_lock(&sbi->stat_lock);
> @@ -2396,7 +2399,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>  	}
>  out_err:
>  	f2fs_up_write(&sbi->cp_global_sem);
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
>  	thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
>  	return err;
>  }
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index e4a8daf433a8..776b0df828ed 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -462,7 +462,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
>  			.should_migrate_blocks = false,
>  			.err_gc_skipped = false,
>  			.nr_free_secs = 1 };
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>  		stat_inc_gc_call_count(sbi, FOREGROUND);
>  		f2fs_gc(sbi, &gc_control);
>  	}
> @@ -3373,10 +3373,10 @@ int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
>  	f2fs_unlock_op(sbi, &lc);
>  
>  	if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  		err = f2fs_gc_range(sbi, 0, sbi->first_seq_zone_segno - 1,
>  				true, ZONED_PIN_SEC_REQUIRED_COUNT);
> -		f2fs_up_write(&sbi->gc_lock);
> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  
>  		gc_required = false;
>  		if (!err)
> @@ -3496,6 +3496,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
>  	block_t start_block, end_block;
>  	struct cp_control cpc;
>  	struct discard_policy dpolicy;
> +	struct f2fs_lock_context lc;
>  	unsigned long long trimmed = 0;
>  	int err = 0;
>  	bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
> @@ -3528,10 +3529,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
>  	if (sbi->discard_blks == 0)
>  		goto out;
>  
> -	f2fs_down_write(&sbi->gc_lock);
> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  	stat_inc_cp_call_count(sbi, TOTAL_CALL);
>  	err = f2fs_write_checkpoint(sbi, &cpc);
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  	if (err)
>  		goto out;
>  
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index d8e5e8652d97..abb468eb4394 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -2563,6 +2563,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>  	int err = 0;
>  	int ret;
>  	block_t unusable;
> +	struct f2fs_lock_context lc;
>  
>  	if (s_flags & SB_RDONLY) {
>  		f2fs_err(sbi, "checkpoint=disable on readonly fs");
> @@ -2588,9 +2589,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>  			.no_bg_gc = true,
>  			.nr_free_secs = 1 };
>  
> -		f2fs_down_write(&sbi->gc_lock);
> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  		stat_inc_gc_call_count(sbi, FOREGROUND);
>  		err = f2fs_gc(sbi, &gc_control);
> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);

^--- this looks wrong?

>  		if (err == -ENODATA) {
>  			err = 0;
>  			break;
> @@ -2612,7 +2614,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>  	}
>  
>  skip_gc:
> -	f2fs_down_write(&sbi->gc_lock);
> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  	cpc.reason = CP_PAUSE;
>  	set_sbi_flag(sbi, SBI_CP_DISABLED);
>  	stat_inc_cp_call_count(sbi, TOTAL_CALL);
> @@ -2625,7 +2627,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>  	spin_unlock(&sbi->stat_lock);
>  
>  out_unlock:
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  restore_flag:
>  	sbi->gc_mode = gc_mode;
>  	sbi->sb->s_flags = s_flags;	/* Restore SB_RDONLY status */
> @@ -2638,6 +2640,7 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
>  	unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16;
>  	long long start, writeback, lock, sync_inode, end;
>  	int ret;
> +	struct f2fs_lock_context lc;
>  
>  	f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld",
>  					__func__,
> @@ -2672,12 +2675,12 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
>  
>  	sync_inode = ktime_get();
>  
> -	f2fs_down_write(&sbi->gc_lock);
> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>  	f2fs_dirty_to_prefree(sbi);
>  
>  	clear_sbi_flag(sbi, SBI_CP_DISABLED);
>  	set_sbi_flag(sbi, SBI_IS_DIRTY);
> -	f2fs_up_write(&sbi->gc_lock);
> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>  
>  	f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld",
>  					__func__,
> @@ -4893,7 +4896,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
>  	sbi->sb = sb;
>  
>  	/* initialize locks within allocated memory */
> -	init_f2fs_rwsem(&sbi->gc_lock);
> +	init_f2fs_rwsem_trace(&sbi->gc_lock, sbi, LOCK_NAME_GC_LOCK);
>  	mutex_init(&sbi->writepages);
>  	init_f2fs_rwsem(&sbi->cp_global_sem);
>  	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> index e5cfb8ad0d5e..bf353e7e024d 100644
> --- a/include/trace/events/f2fs.h
> +++ b/include/trace/events/f2fs.h
> @@ -188,7 +188,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
>  	__print_symbolic(lock,						\
>  		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
>  		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
> -		{ LOCK_NAME_NODE_WRITE,		"node_write" })
> +		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
> +		{ LOCK_NAME_GC_LOCK,		"gc_lock" })
>  
>  struct f2fs_sb_info;
>  struct f2fs_io_info;
> -- 
> 2.49.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock
  2026-01-04  5:35   ` Jaegeuk Kim
@ 2026-01-04  5:42     ` Jaegeuk Kim
  2026-01-04  6:27       ` Chao Yu
  0 siblings, 1 reply; 19+ messages in thread
From: Jaegeuk Kim @ 2026-01-04  5:42 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel

Should be like this?

--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -2639,12 +2639,12 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
                        .should_migrate_blocks = false,
                        .err_gc_skipped = true,
                        .no_bg_gc = true,
-                       .nr_free_secs = 1 };
+                       .nr_free_secs = 1,
+                       .lc };

-               f2fs_down_write_trace(&sbi->gc_lock, &lc);
+               f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
                stat_inc_gc_call_count(sbi, FOREGROUND);
                err = f2fs_gc(sbi, &gc_control);
-               f2fs_up_write_trace(&sbi->gc_lock, &lc);
                if (err == -ENODATA) {
                        err = 0;
                        break;

On 01/04, Jaegeuk Kim wrote:
> On 01/04, Chao Yu wrote:
> > Use f2fs_{down,up}_write_trace for gc_lock to trace lock elapsed time.
> > 
> > Signed-off-by: Chao Yu <chao@kernel.org>
> > ---
> >  fs/f2fs/checkpoint.c        | 10 ++++++----
> >  fs/f2fs/f2fs.h              | 22 ++++++++++++----------
> >  fs/f2fs/file.c              | 13 +++++++------
> >  fs/f2fs/gc.c                | 23 +++++++++++++----------
> >  fs/f2fs/segment.c           | 11 ++++++-----
> >  fs/f2fs/super.c             | 15 +++++++++------
> >  include/trace/events/f2fs.h |  3 ++-
> >  7 files changed, 55 insertions(+), 42 deletions(-)
> > 
> > diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> > index dfd54cba1b35..da7bcfa2a178 100644
> > --- a/fs/f2fs/checkpoint.c
> > +++ b/fs/f2fs/checkpoint.c
> > @@ -1930,11 +1930,12 @@ void f2fs_destroy_checkpoint_caches(void)
> >  static int __write_checkpoint_sync(struct f2fs_sb_info *sbi)
> >  {
> >  	struct cp_control cpc = { .reason = CP_SYNC, };
> > +	struct f2fs_lock_context lc;
> >  	int err;
> >  
> > -	f2fs_down_write(&sbi->gc_lock);
> > +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  	err = f2fs_write_checkpoint(sbi, &cpc);
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  
> >  	return err;
> >  }
> > @@ -2022,11 +2023,12 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
> >  	cpc.reason = __get_cp_reason(sbi);
> >  	if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC ||
> >  		sbi->umount_lock_holder == current) {
> > +		struct f2fs_lock_context lc;
> >  		int ret;
> >  
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  		ret = f2fs_write_checkpoint(sbi, &cpc);
> > -		f2fs_up_write(&sbi->gc_lock);
> > +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  
> >  		return ret;
> >  	}
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index 3f6278ba620d..5b6e632b37a9 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -178,6 +178,7 @@ enum f2fs_lock_name {
> >  	LOCK_NAME_CP_RWSEM,
> >  	LOCK_NAME_NODE_CHANGE,
> >  	LOCK_NAME_NODE_WRITE,
> > +	LOCK_NAME_GC_LOCK,
> >  };
> >  
> >  /*
> > @@ -1408,16 +1409,6 @@ struct atgc_management {
> >  	unsigned long long age_threshold;	/* age threshold */
> >  };
> >  
> > -struct f2fs_gc_control {
> > -	unsigned int victim_segno;	/* target victim segment number */
> > -	int init_gc_type;		/* FG_GC or BG_GC */
> > -	bool no_bg_gc;			/* check the space and stop bg_gc */
> > -	bool should_migrate_blocks;	/* should migrate blocks */
> > -	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
> > -	bool one_time;			/* require one time GC in one migration unit */
> > -	unsigned int nr_free_secs;	/* # of free sections to do GC */
> > -};
> > -
> >  struct f2fs_time_stat {
> >  	unsigned long long total_time;		/* total wall clock time */
> >  #ifdef CONFIG_64BIT
> > @@ -1436,6 +1427,17 @@ struct f2fs_lock_context {
> >  	bool lock_trace;
> >  };
> >  
> > +struct f2fs_gc_control {
> > +	unsigned int victim_segno;	/* target victim segment number */
> > +	int init_gc_type;		/* FG_GC or BG_GC */
> > +	bool no_bg_gc;			/* check the space and stop bg_gc */
> > +	bool should_migrate_blocks;	/* should migrate blocks */
> > +	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
> > +	bool one_time;			/* require one time GC in one migration unit */
> > +	unsigned int nr_free_secs;	/* # of free sections to do GC */
> > +	struct f2fs_lock_context lc;	/* lock context for gc_lock */
> > +};
> > +
> >  /*
> >   * For s_flag in struct f2fs_sb_info
> >   * Modification on enum should be synchronized with s_flag array
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 1cdbbc2e1005..ce291f152bc3 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -1928,7 +1928,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
> >  
> >  		if (has_not_enough_free_secs(sbi, 0,
> >  				sbi->reserved_pin_section)) {
> > -			f2fs_down_write(&sbi->gc_lock);
> > +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  			stat_inc_gc_call_count(sbi, FOREGROUND);
> >  			err = f2fs_gc(sbi, &gc_control);
> >  			if (err && err != -ENODATA) {
> > @@ -2779,12 +2779,13 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
> >  		return ret;
> >  
> >  	if (!sync) {
> > -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> > +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
> > +						&gc_control.lc)) {
> >  			ret = -EBUSY;
> >  			goto out;
> >  		}
> >  	} else {
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  	}
> >  
> >  	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
> > @@ -2824,12 +2825,12 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
> >  
> >  do_more:
> >  	if (!range->sync) {
> > -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> > +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
> >  			ret = -EBUSY;
> >  			goto out;
> >  		}
> >  	} else {
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  	}
> >  
> >  	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
> > @@ -3320,7 +3321,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
> >  	end_segno = min(start_segno + range.segments, dev_end_segno);
> >  
> >  	while (start_segno < end_segno) {
> > -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> > +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
> >  			ret = -EBUSY;
> >  			goto out;
> >  		}
> > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> > index 8999829a9559..391e66064c7e 100644
> > --- a/fs/f2fs/gc.c
> > +++ b/fs/f2fs/gc.c
> > @@ -102,21 +102,22 @@ static int gc_thread_func(void *data)
> >  		if (sbi->gc_mode == GC_URGENT_HIGH ||
> >  				sbi->gc_mode == GC_URGENT_MID) {
> >  			wait_ms = gc_th->urgent_sleep_time;
> > -			f2fs_down_write(&sbi->gc_lock);
> > +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  			goto do_gc;
> >  		}
> >  
> >  		if (foreground) {
> > -			f2fs_down_write(&sbi->gc_lock);
> > +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  			goto do_gc;
> > -		} else if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> > +		} else if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
> > +							&gc_control.lc)) {
> >  			stat_other_skip_bggc_count(sbi);
> >  			goto next;
> >  		}
> >  
> >  		if (!is_idle(sbi, GC_TIME)) {
> >  			increase_sleep_time(gc_th, &wait_ms);
> > -			f2fs_up_write(&sbi->gc_lock);
> > +			f2fs_up_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  			stat_io_skip_bggc_count(sbi);
> >  			goto next;
> >  		}
> > @@ -125,7 +126,8 @@ static int gc_thread_func(void *data)
> >  			if (has_enough_free_blocks(sbi,
> >  				gc_th->no_zoned_gc_percent)) {
> >  				wait_ms = gc_th->no_gc_sleep_time;
> > -				f2fs_up_write(&sbi->gc_lock);
> > +				f2fs_up_write_trace(&sbi->gc_lock,
> > +							&gc_control.lc);
> >  				goto next;
> >  			}
> >  			if (wait_ms == gc_th->no_gc_sleep_time)
> > @@ -2046,7 +2048,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
> >  				reserved_segments(sbi),
> >  				prefree_segments(sbi));
> >  
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &gc_control->lc);
> >  
> >  	put_gc_inode(&gc_list);
> >  
> > @@ -2264,6 +2266,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> >  	__u64 old_block_count, shrunk_blocks;
> >  	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
> >  	struct f2fs_lock_context lc;
> > +	struct f2fs_lock_context glc;
> >  	unsigned int secs;
> >  	int err = 0;
> >  	__u32 rem;
> > @@ -2307,7 +2310,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> >  	secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi));
> >  
> >  	/* stop other GC */
> > -	if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
> > +	if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &glc)) {
> >  		err = -EAGAIN;
> >  		goto out_drop_write;
> >  	}
> > @@ -2329,7 +2332,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> >  
> >  out_unlock:
> >  	f2fs_unlock_op(sbi, &lc);
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
> >  out_drop_write:
> >  	mnt_drop_write_file(filp);
> >  	if (err)
> > @@ -2346,7 +2349,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> >  		return -EROFS;
> >  	}
> >  
> > -	f2fs_down_write(&sbi->gc_lock);
> > +	f2fs_down_write_trace(&sbi->gc_lock, &glc);
> >  	f2fs_down_write(&sbi->cp_global_sem);
> >  
> >  	spin_lock(&sbi->stat_lock);
> > @@ -2396,7 +2399,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> >  	}
> >  out_err:
> >  	f2fs_up_write(&sbi->cp_global_sem);
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
> >  	thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
> >  	return err;
> >  }
> > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> > index e4a8daf433a8..776b0df828ed 100644
> > --- a/fs/f2fs/segment.c
> > +++ b/fs/f2fs/segment.c
> > @@ -462,7 +462,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
> >  			.should_migrate_blocks = false,
> >  			.err_gc_skipped = false,
> >  			.nr_free_secs = 1 };
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
> >  		stat_inc_gc_call_count(sbi, FOREGROUND);
> >  		f2fs_gc(sbi, &gc_control);
> >  	}
> > @@ -3373,10 +3373,10 @@ int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
> >  	f2fs_unlock_op(sbi, &lc);
> >  
> >  	if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  		err = f2fs_gc_range(sbi, 0, sbi->first_seq_zone_segno - 1,
> >  				true, ZONED_PIN_SEC_REQUIRED_COUNT);
> > -		f2fs_up_write(&sbi->gc_lock);
> > +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  
> >  		gc_required = false;
> >  		if (!err)
> > @@ -3496,6 +3496,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
> >  	block_t start_block, end_block;
> >  	struct cp_control cpc;
> >  	struct discard_policy dpolicy;
> > +	struct f2fs_lock_context lc;
> >  	unsigned long long trimmed = 0;
> >  	int err = 0;
> >  	bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
> > @@ -3528,10 +3529,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
> >  	if (sbi->discard_blks == 0)
> >  		goto out;
> >  
> > -	f2fs_down_write(&sbi->gc_lock);
> > +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  	stat_inc_cp_call_count(sbi, TOTAL_CALL);
> >  	err = f2fs_write_checkpoint(sbi, &cpc);
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  	if (err)
> >  		goto out;
> >  
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index d8e5e8652d97..abb468eb4394 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -2563,6 +2563,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
> >  	int err = 0;
> >  	int ret;
> >  	block_t unusable;
> > +	struct f2fs_lock_context lc;
> >  
> >  	if (s_flags & SB_RDONLY) {
> >  		f2fs_err(sbi, "checkpoint=disable on readonly fs");
> > @@ -2588,9 +2589,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
> >  			.no_bg_gc = true,
> >  			.nr_free_secs = 1 };
> >  
> > -		f2fs_down_write(&sbi->gc_lock);
> > +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  		stat_inc_gc_call_count(sbi, FOREGROUND);
> >  		err = f2fs_gc(sbi, &gc_control);
> > +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
> 
> ^--- this looks wrong?
> 
> >  		if (err == -ENODATA) {
> >  			err = 0;
> >  			break;
> > @@ -2612,7 +2614,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
> >  	}
> >  
> >  skip_gc:
> > -	f2fs_down_write(&sbi->gc_lock);
> > +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  	cpc.reason = CP_PAUSE;
> >  	set_sbi_flag(sbi, SBI_CP_DISABLED);
> >  	stat_inc_cp_call_count(sbi, TOTAL_CALL);
> > @@ -2625,7 +2627,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
> >  	spin_unlock(&sbi->stat_lock);
> >  
> >  out_unlock:
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  restore_flag:
> >  	sbi->gc_mode = gc_mode;
> >  	sbi->sb->s_flags = s_flags;	/* Restore SB_RDONLY status */
> > @@ -2638,6 +2640,7 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
> >  	unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16;
> >  	long long start, writeback, lock, sync_inode, end;
> >  	int ret;
> > +	struct f2fs_lock_context lc;
> >  
> >  	f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld",
> >  					__func__,
> > @@ -2672,12 +2675,12 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
> >  
> >  	sync_inode = ktime_get();
> >  
> > -	f2fs_down_write(&sbi->gc_lock);
> > +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
> >  	f2fs_dirty_to_prefree(sbi);
> >  
> >  	clear_sbi_flag(sbi, SBI_CP_DISABLED);
> >  	set_sbi_flag(sbi, SBI_IS_DIRTY);
> > -	f2fs_up_write(&sbi->gc_lock);
> > +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
> >  
> >  	f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld",
> >  					__func__,
> > @@ -4893,7 +4896,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
> >  	sbi->sb = sb;
> >  
> >  	/* initialize locks within allocated memory */
> > -	init_f2fs_rwsem(&sbi->gc_lock);
> > +	init_f2fs_rwsem_trace(&sbi->gc_lock, sbi, LOCK_NAME_GC_LOCK);
> >  	mutex_init(&sbi->writepages);
> >  	init_f2fs_rwsem(&sbi->cp_global_sem);
> >  	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
> > diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> > index e5cfb8ad0d5e..bf353e7e024d 100644
> > --- a/include/trace/events/f2fs.h
> > +++ b/include/trace/events/f2fs.h
> > @@ -188,7 +188,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
> >  	__print_symbolic(lock,						\
> >  		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
> >  		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
> > -		{ LOCK_NAME_NODE_WRITE,		"node_write" })
> > +		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
> > +		{ LOCK_NAME_GC_LOCK,		"gc_lock" })
> >  
> >  struct f2fs_sb_info;
> >  struct f2fs_io_info;
> > -- 
> > 2.49.0

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock
  2026-01-04  5:42     ` Jaegeuk Kim
@ 2026-01-04  6:27       ` Chao Yu
  0 siblings, 0 replies; 19+ messages in thread
From: Chao Yu @ 2026-01-04  6:27 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: chao, linux-f2fs-devel, linux-kernel

On 2026/1/4 13:42, Jaegeuk Kim wrote:
> Should be like this?
> 
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -2639,12 +2639,12 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>                          .should_migrate_blocks = false,
>                          .err_gc_skipped = true,
>                          .no_bg_gc = true,
> -                       .nr_free_secs = 1 };
> +                       .nr_free_secs = 1,
> +                       .lc };

No need to initialize .lc? f2fs_down_write_trace() will initialize all fields
in lc.

> 
> -               f2fs_down_write_trace(&sbi->gc_lock, &lc);
> +               f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>                  stat_inc_gc_call_count(sbi, FOREGROUND);
>                  err = f2fs_gc(sbi, &gc_control);
> -               f2fs_up_write_trace(&sbi->gc_lock, &lc);
>                  if (err == -ENODATA) {
>                          err = 0;
>                          break;

Ah, right, thanks for the fix!

Thanks,

> 
> On 01/04, Jaegeuk Kim wrote:
>> On 01/04, Chao Yu wrote:
>>> Use f2fs_{down,up}_write_trace for gc_lock to trace lock elapsed time.
>>>
>>> Signed-off-by: Chao Yu <chao@kernel.org>
>>> ---
>>>   fs/f2fs/checkpoint.c        | 10 ++++++----
>>>   fs/f2fs/f2fs.h              | 22 ++++++++++++----------
>>>   fs/f2fs/file.c              | 13 +++++++------
>>>   fs/f2fs/gc.c                | 23 +++++++++++++----------
>>>   fs/f2fs/segment.c           | 11 ++++++-----
>>>   fs/f2fs/super.c             | 15 +++++++++------
>>>   include/trace/events/f2fs.h |  3 ++-
>>>   7 files changed, 55 insertions(+), 42 deletions(-)
>>>
>>> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
>>> index dfd54cba1b35..da7bcfa2a178 100644
>>> --- a/fs/f2fs/checkpoint.c
>>> +++ b/fs/f2fs/checkpoint.c
>>> @@ -1930,11 +1930,12 @@ void f2fs_destroy_checkpoint_caches(void)
>>>   static int __write_checkpoint_sync(struct f2fs_sb_info *sbi)
>>>   {
>>>   	struct cp_control cpc = { .reason = CP_SYNC, };
>>> +	struct f2fs_lock_context lc;
>>>   	int err;
>>>   
>>> -	f2fs_down_write(&sbi->gc_lock);
>>> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   	err = f2fs_write_checkpoint(sbi, &cpc);
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   
>>>   	return err;
>>>   }
>>> @@ -2022,11 +2023,12 @@ int f2fs_issue_checkpoint(struct f2fs_sb_info *sbi)
>>>   	cpc.reason = __get_cp_reason(sbi);
>>>   	if (!test_opt(sbi, MERGE_CHECKPOINT) || cpc.reason != CP_SYNC ||
>>>   		sbi->umount_lock_holder == current) {
>>> +		struct f2fs_lock_context lc;
>>>   		int ret;
>>>   
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   		ret = f2fs_write_checkpoint(sbi, &cpc);
>>> -		f2fs_up_write(&sbi->gc_lock);
>>> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   
>>>   		return ret;
>>>   	}
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index 3f6278ba620d..5b6e632b37a9 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -178,6 +178,7 @@ enum f2fs_lock_name {
>>>   	LOCK_NAME_CP_RWSEM,
>>>   	LOCK_NAME_NODE_CHANGE,
>>>   	LOCK_NAME_NODE_WRITE,
>>> +	LOCK_NAME_GC_LOCK,
>>>   };
>>>   
>>>   /*
>>> @@ -1408,16 +1409,6 @@ struct atgc_management {
>>>   	unsigned long long age_threshold;	/* age threshold */
>>>   };
>>>   
>>> -struct f2fs_gc_control {
>>> -	unsigned int victim_segno;	/* target victim segment number */
>>> -	int init_gc_type;		/* FG_GC or BG_GC */
>>> -	bool no_bg_gc;			/* check the space and stop bg_gc */
>>> -	bool should_migrate_blocks;	/* should migrate blocks */
>>> -	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
>>> -	bool one_time;			/* require one time GC in one migration unit */
>>> -	unsigned int nr_free_secs;	/* # of free sections to do GC */
>>> -};
>>> -
>>>   struct f2fs_time_stat {
>>>   	unsigned long long total_time;		/* total wall clock time */
>>>   #ifdef CONFIG_64BIT
>>> @@ -1436,6 +1427,17 @@ struct f2fs_lock_context {
>>>   	bool lock_trace;
>>>   };
>>>   
>>> +struct f2fs_gc_control {
>>> +	unsigned int victim_segno;	/* target victim segment number */
>>> +	int init_gc_type;		/* FG_GC or BG_GC */
>>> +	bool no_bg_gc;			/* check the space and stop bg_gc */
>>> +	bool should_migrate_blocks;	/* should migrate blocks */
>>> +	bool err_gc_skipped;		/* return EAGAIN if GC skipped */
>>> +	bool one_time;			/* require one time GC in one migration unit */
>>> +	unsigned int nr_free_secs;	/* # of free sections to do GC */
>>> +	struct f2fs_lock_context lc;	/* lock context for gc_lock */
>>> +};
>>> +
>>>   /*
>>>    * For s_flag in struct f2fs_sb_info
>>>    * Modification on enum should be synchronized with s_flag array
>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
>>> index 1cdbbc2e1005..ce291f152bc3 100644
>>> --- a/fs/f2fs/file.c
>>> +++ b/fs/f2fs/file.c
>>> @@ -1928,7 +1928,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
>>>   
>>>   		if (has_not_enough_free_secs(sbi, 0,
>>>   				sbi->reserved_pin_section)) {
>>> -			f2fs_down_write(&sbi->gc_lock);
>>> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   			stat_inc_gc_call_count(sbi, FOREGROUND);
>>>   			err = f2fs_gc(sbi, &gc_control);
>>>   			if (err && err != -ENODATA) {
>>> @@ -2779,12 +2779,13 @@ static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
>>>   		return ret;
>>>   
>>>   	if (!sync) {
>>> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
>>> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
>>> +						&gc_control.lc)) {
>>>   			ret = -EBUSY;
>>>   			goto out;
>>>   		}
>>>   	} else {
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   	}
>>>   
>>>   	gc_control.init_gc_type = sync ? FG_GC : BG_GC;
>>> @@ -2824,12 +2825,12 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
>>>   
>>>   do_more:
>>>   	if (!range->sync) {
>>> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
>>> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
>>>   			ret = -EBUSY;
>>>   			goto out;
>>>   		}
>>>   	} else {
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   	}
>>>   
>>>   	gc_control.victim_segno = GET_SEGNO(sbi, range->start);
>>> @@ -3320,7 +3321,7 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
>>>   	end_segno = min(start_segno + range.segments, dev_end_segno);
>>>   
>>>   	while (start_segno < end_segno) {
>>> -		if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
>>> +		if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &gc_control.lc)) {
>>>   			ret = -EBUSY;
>>>   			goto out;
>>>   		}
>>> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
>>> index 8999829a9559..391e66064c7e 100644
>>> --- a/fs/f2fs/gc.c
>>> +++ b/fs/f2fs/gc.c
>>> @@ -102,21 +102,22 @@ static int gc_thread_func(void *data)
>>>   		if (sbi->gc_mode == GC_URGENT_HIGH ||
>>>   				sbi->gc_mode == GC_URGENT_MID) {
>>>   			wait_ms = gc_th->urgent_sleep_time;
>>> -			f2fs_down_write(&sbi->gc_lock);
>>> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   			goto do_gc;
>>>   		}
>>>   
>>>   		if (foreground) {
>>> -			f2fs_down_write(&sbi->gc_lock);
>>> +			f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   			goto do_gc;
>>> -		} else if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
>>> +		} else if (!f2fs_down_write_trylock_trace(&sbi->gc_lock,
>>> +							&gc_control.lc)) {
>>>   			stat_other_skip_bggc_count(sbi);
>>>   			goto next;
>>>   		}
>>>   
>>>   		if (!is_idle(sbi, GC_TIME)) {
>>>   			increase_sleep_time(gc_th, &wait_ms);
>>> -			f2fs_up_write(&sbi->gc_lock);
>>> +			f2fs_up_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   			stat_io_skip_bggc_count(sbi);
>>>   			goto next;
>>>   		}
>>> @@ -125,7 +126,8 @@ static int gc_thread_func(void *data)
>>>   			if (has_enough_free_blocks(sbi,
>>>   				gc_th->no_zoned_gc_percent)) {
>>>   				wait_ms = gc_th->no_gc_sleep_time;
>>> -				f2fs_up_write(&sbi->gc_lock);
>>> +				f2fs_up_write_trace(&sbi->gc_lock,
>>> +							&gc_control.lc);
>>>   				goto next;
>>>   			}
>>>   			if (wait_ms == gc_th->no_gc_sleep_time)
>>> @@ -2046,7 +2048,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control)
>>>   				reserved_segments(sbi),
>>>   				prefree_segments(sbi));
>>>   
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &gc_control->lc);
>>>   
>>>   	put_gc_inode(&gc_list);
>>>   
>>> @@ -2264,6 +2266,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>>>   	__u64 old_block_count, shrunk_blocks;
>>>   	struct cp_control cpc = { CP_RESIZE, 0, 0, 0 };
>>>   	struct f2fs_lock_context lc;
>>> +	struct f2fs_lock_context glc;
>>>   	unsigned int secs;
>>>   	int err = 0;
>>>   	__u32 rem;
>>> @@ -2307,7 +2310,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>>>   	secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi));
>>>   
>>>   	/* stop other GC */
>>> -	if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
>>> +	if (!f2fs_down_write_trylock_trace(&sbi->gc_lock, &glc)) {
>>>   		err = -EAGAIN;
>>>   		goto out_drop_write;
>>>   	}
>>> @@ -2329,7 +2332,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>>>   
>>>   out_unlock:
>>>   	f2fs_unlock_op(sbi, &lc);
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
>>>   out_drop_write:
>>>   	mnt_drop_write_file(filp);
>>>   	if (err)
>>> @@ -2346,7 +2349,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>>>   		return -EROFS;
>>>   	}
>>>   
>>> -	f2fs_down_write(&sbi->gc_lock);
>>> +	f2fs_down_write_trace(&sbi->gc_lock, &glc);
>>>   	f2fs_down_write(&sbi->cp_global_sem);
>>>   
>>>   	spin_lock(&sbi->stat_lock);
>>> @@ -2396,7 +2399,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
>>>   	}
>>>   out_err:
>>>   	f2fs_up_write(&sbi->cp_global_sem);
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &glc);
>>>   	thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
>>>   	return err;
>>>   }
>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
>>> index e4a8daf433a8..776b0df828ed 100644
>>> --- a/fs/f2fs/segment.c
>>> +++ b/fs/f2fs/segment.c
>>> @@ -462,7 +462,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
>>>   			.should_migrate_blocks = false,
>>>   			.err_gc_skipped = false,
>>>   			.nr_free_secs = 1 };
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &gc_control.lc);
>>>   		stat_inc_gc_call_count(sbi, FOREGROUND);
>>>   		f2fs_gc(sbi, &gc_control);
>>>   	}
>>> @@ -3373,10 +3373,10 @@ int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi)
>>>   	f2fs_unlock_op(sbi, &lc);
>>>   
>>>   	if (f2fs_sb_has_blkzoned(sbi) && err == -EAGAIN && gc_required) {
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   		err = f2fs_gc_range(sbi, 0, sbi->first_seq_zone_segno - 1,
>>>   				true, ZONED_PIN_SEC_REQUIRED_COUNT);
>>> -		f2fs_up_write(&sbi->gc_lock);
>>> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   
>>>   		gc_required = false;
>>>   		if (!err)
>>> @@ -3496,6 +3496,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
>>>   	block_t start_block, end_block;
>>>   	struct cp_control cpc;
>>>   	struct discard_policy dpolicy;
>>> +	struct f2fs_lock_context lc;
>>>   	unsigned long long trimmed = 0;
>>>   	int err = 0;
>>>   	bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
>>> @@ -3528,10 +3529,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
>>>   	if (sbi->discard_blks == 0)
>>>   		goto out;
>>>   
>>> -	f2fs_down_write(&sbi->gc_lock);
>>> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   	stat_inc_cp_call_count(sbi, TOTAL_CALL);
>>>   	err = f2fs_write_checkpoint(sbi, &cpc);
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   	if (err)
>>>   		goto out;
>>>   
>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>>> index d8e5e8652d97..abb468eb4394 100644
>>> --- a/fs/f2fs/super.c
>>> +++ b/fs/f2fs/super.c
>>> @@ -2563,6 +2563,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>>>   	int err = 0;
>>>   	int ret;
>>>   	block_t unusable;
>>> +	struct f2fs_lock_context lc;
>>>   
>>>   	if (s_flags & SB_RDONLY) {
>>>   		f2fs_err(sbi, "checkpoint=disable on readonly fs");
>>> @@ -2588,9 +2589,10 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>>>   			.no_bg_gc = true,
>>>   			.nr_free_secs = 1 };
>>>   
>>> -		f2fs_down_write(&sbi->gc_lock);
>>> +		f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   		stat_inc_gc_call_count(sbi, FOREGROUND);
>>>   		err = f2fs_gc(sbi, &gc_control);
>>> +		f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>
>> ^--- this looks wrong?
>>
>>>   		if (err == -ENODATA) {
>>>   			err = 0;
>>>   			break;
>>> @@ -2612,7 +2614,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>>>   	}
>>>   
>>>   skip_gc:
>>> -	f2fs_down_write(&sbi->gc_lock);
>>> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   	cpc.reason = CP_PAUSE;
>>>   	set_sbi_flag(sbi, SBI_CP_DISABLED);
>>>   	stat_inc_cp_call_count(sbi, TOTAL_CALL);
>>> @@ -2625,7 +2627,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
>>>   	spin_unlock(&sbi->stat_lock);
>>>   
>>>   out_unlock:
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   restore_flag:
>>>   	sbi->gc_mode = gc_mode;
>>>   	sbi->sb->s_flags = s_flags;	/* Restore SB_RDONLY status */
>>> @@ -2638,6 +2640,7 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
>>>   	unsigned int nr_pages = get_pages(sbi, F2FS_DIRTY_DATA) / 16;
>>>   	long long start, writeback, lock, sync_inode, end;
>>>   	int ret;
>>> +	struct f2fs_lock_context lc;
>>>   
>>>   	f2fs_info(sbi, "%s start, meta: %lld, node: %lld, data: %lld",
>>>   					__func__,
>>> @@ -2672,12 +2675,12 @@ static int f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
>>>   
>>>   	sync_inode = ktime_get();
>>>   
>>> -	f2fs_down_write(&sbi->gc_lock);
>>> +	f2fs_down_write_trace(&sbi->gc_lock, &lc);
>>>   	f2fs_dirty_to_prefree(sbi);
>>>   
>>>   	clear_sbi_flag(sbi, SBI_CP_DISABLED);
>>>   	set_sbi_flag(sbi, SBI_IS_DIRTY);
>>> -	f2fs_up_write(&sbi->gc_lock);
>>> +	f2fs_up_write_trace(&sbi->gc_lock, &lc);
>>>   
>>>   	f2fs_info(sbi, "%s sync_fs, meta: %lld, imeta: %lld, node: %lld, dents: %lld, qdata: %lld",
>>>   					__func__,
>>> @@ -4893,7 +4896,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
>>>   	sbi->sb = sb;
>>>   
>>>   	/* initialize locks within allocated memory */
>>> -	init_f2fs_rwsem(&sbi->gc_lock);
>>> +	init_f2fs_rwsem_trace(&sbi->gc_lock, sbi, LOCK_NAME_GC_LOCK);
>>>   	mutex_init(&sbi->writepages);
>>>   	init_f2fs_rwsem(&sbi->cp_global_sem);
>>>   	init_f2fs_rwsem_trace(&sbi->node_write, sbi, LOCK_NAME_NODE_WRITE);
>>> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
>>> index e5cfb8ad0d5e..bf353e7e024d 100644
>>> --- a/include/trace/events/f2fs.h
>>> +++ b/include/trace/events/f2fs.h
>>> @@ -188,7 +188,8 @@ TRACE_DEFINE_ENUM(CP_PHASE_FINISH_CHECKPOINT);
>>>   	__print_symbolic(lock,						\
>>>   		{ LOCK_NAME_CP_RWSEM,		"cp_rwsem" },		\
>>>   		{ LOCK_NAME_NODE_CHANGE,	"node_change" },	\
>>> -		{ LOCK_NAME_NODE_WRITE,		"node_write" })
>>> +		{ LOCK_NAME_NODE_WRITE,		"node_write" },		\
>>> +		{ LOCK_NAME_GC_LOCK,		"gc_lock" })
>>>   
>>>   struct f2fs_sb_info;
>>>   struct f2fs_io_info;
>>> -- 
>>> 2.49.0


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [f2fs-dev] [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore
  2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
                   ` (13 preceding siblings ...)
  2026-01-04  5:28 ` [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Jaegeuk Kim
@ 2026-01-07  3:30 ` patchwork-bot+f2fs
  14 siblings, 0 replies; 19+ messages in thread
From: patchwork-bot+f2fs @ 2026-01-07  3:30 UTC (permalink / raw)
  To: Chao Yu; +Cc: jaegeuk, linux-kernel, linux-f2fs-devel

Hello:

This series was applied to jaegeuk/f2fs.git (dev)
by Jaegeuk Kim <jaegeuk@kernel.org>:

On Sun,  4 Jan 2026 10:07:16 +0800 you wrote:
> This patch adds lock elapsed time trace facility for f2fs rwsemphore.
> 
> If total elapsed time of critical region covered by lock exceeds a
> threshold, it will print tracepoint to dump information of lock related
> context, including:
> - thread information
> - CPU/IO priority
> - lock information
> - elapsed time
>  - total time
>  - running time (depend on CONFIG_64BIT)
>  - runnable time (depend on CONFIG_SCHED_INFO and CONFIG_SCHEDSTATS)
>  - io sleep time (depend on CONFIG_TASK_DELAY_ACCT and
> 		  /proc/sys/kernel/task_delayacct)
>  - other time    (by default other time will account nonio sleep time,
>                   but, if above kconfig is not defined, other time will
>                   include runnable time and/or io sleep time as wll)
> 
> [...]

Here is the summary with links:
  - [f2fs-dev,01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore
    https://git.kernel.org/jaegeuk/f2fs/c/79b3cebc70fc
  - [f2fs-dev,02/14] f2fs: sysfs: introduce max_lock_elapsed_time
    https://git.kernel.org/jaegeuk/f2fs/c/e4b75621fc43
  - [f2fs-dev,03/14] f2fs: trace elapsed time for cp_rwsem lock
    https://git.kernel.org/jaegeuk/f2fs/c/66e9e0d55d11
  - [f2fs-dev,04/14] f2fs: trace elapsed time for node_change lock
    https://git.kernel.org/jaegeuk/f2fs/c/f9f93602512b
  - [f2fs-dev,05/14] f2fs: trace elapsed time for node_write lock
    https://git.kernel.org/jaegeuk/f2fs/c/bb28b66875cc
  - [f2fs-dev,06/14] f2fs: trace elapsed time for gc_lock lock
    (no matching commit)
  - [f2fs-dev,07/14] f2fs: trace elapsed time for cp_global_sem lock
    https://git.kernel.org/jaegeuk/f2fs/c/ce9fe67c9cdb
  - [f2fs-dev,08/14] f2fs: trace elapsed time for io_rwsem lock
    https://git.kernel.org/jaegeuk/f2fs/c/67972c2b8974
  - [f2fs-dev,09/14] f2fs: clean up w/ __f2fs_schedule_timeout()
    https://git.kernel.org/jaegeuk/f2fs/c/b5da276ae6ab
  - [f2fs-dev,10/14] f2fs: fix to use jiffies based precision for DEFAULT_SCHEDULE_TIMEOUT
    https://git.kernel.org/jaegeuk/f2fs/c/da90b6715567
  - [f2fs-dev,11/14] f2fs: fix timeout precision of f2fs_io_schedule_timeout_killable()
    https://git.kernel.org/jaegeuk/f2fs/c/6fa116053951
  - [f2fs-dev,12/14] f2fs: rename FAULT_TIMEOUT to FAULT_ATOMIC_TIMEOUT
    https://git.kernel.org/jaegeuk/f2fs/c/7a127c80b0ee
  - [f2fs-dev,13/14] f2fs: introduce FAULT_LOCK_TIMEOUT
    https://git.kernel.org/jaegeuk/f2fs/c/c56254e2e042
  - [f2fs-dev,14/14] f2fs: sysfs: introduce inject_lock_timeout
    https://git.kernel.org/jaegeuk/f2fs/c/d36de29f4bb5

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-01-07  3:33 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-04  2:07 [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Chao Yu
2026-01-04  2:07 ` [PATCH 02/14] f2fs: sysfs: introduce max_lock_elapsed_time Chao Yu
2026-01-04  2:07 ` [PATCH 03/14] f2fs: trace elapsed time for cp_rwsem lock Chao Yu
2026-01-04  2:07 ` [PATCH 04/14] f2fs: trace elapsed time for node_change lock Chao Yu
2026-01-04  2:07 ` [PATCH 05/14] f2fs: trace elapsed time for node_write lock Chao Yu
2026-01-04  2:07 ` [PATCH 06/14] f2fs: trace elapsed time for gc_lock lock Chao Yu
2026-01-04  5:35   ` Jaegeuk Kim
2026-01-04  5:42     ` Jaegeuk Kim
2026-01-04  6:27       ` Chao Yu
2026-01-04  2:07 ` [PATCH 07/14] f2fs: trace elapsed time for cp_global_sem lock Chao Yu
2026-01-04  2:07 ` [PATCH 08/14] f2fs: trace elapsed time for io_rwsem lock Chao Yu
2026-01-04  2:07 ` [PATCH 09/14] f2fs: clean up w/ __f2fs_schedule_timeout() Chao Yu
2026-01-04  2:07 ` [PATCH 10/14] f2fs: fix to use jiffies based precision for DEFAULT_SCHEDULE_TIMEOUT Chao Yu
2026-01-04  2:07 ` [PATCH 11/14] f2fs: fix timeout precision of f2fs_io_schedule_timeout_killable() Chao Yu
2026-01-04  2:07 ` [PATCH 12/14] f2fs: rename FAULT_TIMEOUT to FAULT_ATOMIC_TIMEOUT Chao Yu
2026-01-04  2:07 ` [PATCH 13/14] f2fs: introduce FAULT_LOCK_TIMEOUT Chao Yu
2026-01-04  2:07 ` [PATCH 14/14] f2fs: sysfs: introduce inject_lock_timeout Chao Yu
2026-01-04  5:28 ` [PATCH 01/14] f2fs: add lock elapsed time trace facility for f2fs rwsemphore Jaegeuk Kim
2026-01-07  3:30 ` [f2fs-dev] " patchwork-bot+f2fs

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox