ext4: prevent an infinite loop in the lazyinit thread

Use ktime_get_ns instead of ktime_get_real_ns when computing the lr_timeout
not to be affected by system time jumps.

Use a boolean instead of the MAX_JIFFY_OFFSET value to determine whether
the next_wakeup value has been set. Comparing elr->lr_next_sched to
MAX_JIFFY_OFFSET can cause the lazyinit thread to loop indefinitely.

Co-developed-by: Lukas Skupinski <lukas.skupinski@landisgyr.com>
Signed-off-by: Lukas Skupinski <lukas.skupinski@landisgyr.com>
Signed-off-by: Mathieu Othacehe <othacehe@gnu.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20241106134741.26948-2-othacehe@gnu.org
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Mathieu Othacehe 2024-11-06 14:47:41 +01:00 committed by Theodore Ts'o
parent d5e9836e13
commit e06a8c24f6

View File

@ -3719,12 +3719,12 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
ret = 1;
if (!ret) {
start_time = ktime_get_real_ns();
start_time = ktime_get_ns();
ret = ext4_init_inode_table(sb, group,
elr->lr_timeout ? 0 : 1);
trace_ext4_lazy_itable_init(sb, group);
if (elr->lr_timeout == 0) {
elr->lr_timeout = nsecs_to_jiffies((ktime_get_real_ns() - start_time) *
elr->lr_timeout = nsecs_to_jiffies((ktime_get_ns() - start_time) *
EXT4_SB(elr->lr_super)->s_li_wait_mult);
}
elr->lr_next_sched = jiffies + elr->lr_timeout;
@ -3784,8 +3784,9 @@ static int ext4_lazyinit_thread(void *arg)
cont_thread:
while (true) {
next_wakeup = MAX_JIFFY_OFFSET;
bool next_wakeup_initialized = false;
next_wakeup = 0;
mutex_lock(&eli->li_list_mtx);
if (list_empty(&eli->li_request_list)) {
mutex_unlock(&eli->li_list_mtx);
@ -3798,8 +3799,11 @@ static int ext4_lazyinit_thread(void *arg)
lr_request);
if (time_before(jiffies, elr->lr_next_sched)) {
if (time_before(elr->lr_next_sched, next_wakeup))
if (!next_wakeup_initialized ||
time_before(elr->lr_next_sched, next_wakeup)) {
next_wakeup = elr->lr_next_sched;
next_wakeup_initialized = true;
}
continue;
}
if (down_read_trylock(&elr->lr_super->s_umount)) {
@ -3827,16 +3831,18 @@ static int ext4_lazyinit_thread(void *arg)
elr->lr_next_sched = jiffies +
get_random_u32_below(EXT4_DEF_LI_MAX_START_DELAY * HZ);
}
if (time_before(elr->lr_next_sched, next_wakeup))
if (!next_wakeup_initialized ||
time_before(elr->lr_next_sched, next_wakeup)) {
next_wakeup = elr->lr_next_sched;
next_wakeup_initialized = true;
}
}
mutex_unlock(&eli->li_list_mtx);
try_to_freeze();
cur = jiffies;
if ((time_after_eq(cur, next_wakeup)) ||
(MAX_JIFFY_OFFSET == next_wakeup)) {
if (!next_wakeup_initialized || time_after_eq(cur, next_wakeup)) {
cond_resched();
continue;
}