mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 15:36:55 +08:00
f2fs: sysfs: introduce inject_lock_timeout
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> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
@@ -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
|
||||
========== ===============================
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ next:
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -529,6 +530,12 @@ out:
|
||||
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);
|
||||
@@ -1233,6 +1240,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 */
|
||||
@@ -1362,6 +1370,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),
|
||||
|
||||
Reference in New Issue
Block a user