mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02: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:
parent
c56254e2e0
commit
d36de29f4b
|
|
@ -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
|
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,
|
of related context. This sysfs entry can be used to control the value of threshold,
|
||||||
by default, the value is 500 ms.
|
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;
|
return;
|
||||||
|
|
||||||
if (time_to_inject(sem->sbi, FAULT_LOCK_TIMEOUT))
|
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);
|
get_lock_elapsed_time(&tts);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,8 @@ enum {
|
||||||
enum fault_option {
|
enum fault_option {
|
||||||
FAULT_RATE = 1, /* only update fault rate */
|
FAULT_RATE = 1, /* only update fault rate */
|
||||||
FAULT_TYPE = 2, /* only update fault type */
|
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
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
|
|
@ -83,6 +84,7 @@ struct f2fs_fault_info {
|
||||||
unsigned int inject_type;
|
unsigned int inject_type;
|
||||||
/* Used to account total count of injection for each type */
|
/* Used to account total count of injection for each type */
|
||||||
unsigned int inject_count[FAULT_MAX];
|
unsigned int inject_count[FAULT_MAX];
|
||||||
|
unsigned int inject_lock_timeout; /* inject lock timeout */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char *f2fs_fault_name[FAULT_MAX];
|
extern const char *f2fs_fault_name[FAULT_MAX];
|
||||||
|
|
@ -184,6 +186,15 @@ enum f2fs_lock_name {
|
||||||
LOCK_NAME_IO_RWSEM,
|
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
|
* An implementation of an rwsem that is explicitly unfair to readers. This
|
||||||
* prevents priority inversion when a low-priority reader acquires the read lock
|
* 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
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
extern int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
|
extern int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
|
||||||
unsigned long type, enum fault_option fo);
|
unsigned long type, enum fault_option fo);
|
||||||
|
extern void f2fs_simulate_lock_timeout(struct f2fs_sb_info *sbi);
|
||||||
#else
|
#else
|
||||||
static inline int f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
|
static inline int f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
|
||||||
unsigned long rate, unsigned long type,
|
unsigned long rate, unsigned long type,
|
||||||
|
|
@ -4934,6 +4946,10 @@ static inline int f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline void f2fs_simulate_lock_timeout(struct f2fs_sb_info *sbi)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline bool is_journalled_quota(struct f2fs_sb_info *sbi)
|
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) \
|
#define f2fs_schedule_timeout(timeout) \
|
||||||
__f2fs_schedule_timeout(timeout, false)
|
__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;
|
unsigned long last_time = jiffies + timeout;
|
||||||
|
|
||||||
while (jiffies < last_time) {
|
while (jiffies < last_time) {
|
||||||
if (fatal_signal_pending(current))
|
if (fatal_signal_pending(current))
|
||||||
return;
|
return;
|
||||||
__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, true);
|
__f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT, io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,7 @@ static int __f2fs_commit_atomic_write(struct inode *inode)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (time_to_inject(sbi, FAULT_ATOMIC_TIMEOUT))
|
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) {
|
if (ret) {
|
||||||
sbi->revoked_atomic_block += fi->atomic_write_cnt;
|
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);
|
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;
|
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
|
#endif
|
||||||
|
|
||||||
/* f2fs-wide shrinker description */
|
/* f2fs-wide shrinker description */
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ enum {
|
||||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
FAULT_INFO_RATE, /* struct f2fs_fault_info */
|
FAULT_INFO_RATE, /* struct f2fs_fault_info */
|
||||||
FAULT_INFO_TYPE, /* struct f2fs_fault_info */
|
FAULT_INFO_TYPE, /* struct f2fs_fault_info */
|
||||||
|
FAULT_INFO_TIMEOUT, /* struct f2fs_fault_info */
|
||||||
#endif
|
#endif
|
||||||
RESERVED_BLOCKS, /* struct f2fs_sb_info */
|
RESERVED_BLOCKS, /* struct f2fs_sb_info */
|
||||||
CPRC_INFO, /* struct ckpt_req_control */
|
CPRC_INFO, /* struct ckpt_req_control */
|
||||||
|
|
@ -529,6 +530,12 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return count;
|
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
|
#endif
|
||||||
if (a->struct_type == RESERVED_BLOCKS) {
|
if (a->struct_type == RESERVED_BLOCKS) {
|
||||||
spin_lock(&sbi->stat_lock);
|
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
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_RATE, inject_rate);
|
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_TYPE, inject_type);
|
||||||
|
FAULT_INFO_GENERAL_RW_ATTR(FAULT_INFO_TIMEOUT, inject_lock_timeout);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* RESERVED_BLOCKS ATTR */
|
/* RESERVED_BLOCKS ATTR */
|
||||||
|
|
@ -1362,6 +1370,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
ATTR_LIST(inject_rate),
|
ATTR_LIST(inject_rate),
|
||||||
ATTR_LIST(inject_type),
|
ATTR_LIST(inject_type),
|
||||||
|
ATTR_LIST(inject_lock_timeout),
|
||||||
#endif
|
#endif
|
||||||
ATTR_LIST(data_io_flag),
|
ATTR_LIST(data_io_flag),
|
||||||
ATTR_LIST(node_io_flag),
|
ATTR_LIST(node_io_flag),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user