Skip to content

Commit f5d39b0

Browse files
author
Peter Zijlstra
committed
freezer,sched: Rewrite core freezer logic
Rewrite the core freezer to behave better wrt thawing and be simpler in general. By replacing PF_FROZEN with TASK_FROZEN, a special block state, it is ensured frozen tasks stay frozen until thawed and don't randomly wake up early, as is currently possible. As such, it does away with PF_FROZEN and PF_FREEZER_SKIP, freeing up two PF_flags (yay!). Specifically; the current scheme works a little like: freezer_do_not_count(); schedule(); freezer_count(); And either the task is blocked, or it lands in try_to_freezer() through freezer_count(). Now, when it is blocked, the freezer considers it frozen and continues. However, on thawing, once pm_freezing is cleared, freezer_count() stops working, and any random/spurious wakeup will let a task run before its time. That is, thawing tries to thaw things in explicit order; kernel threads and workqueues before doing bringing SMP back before userspace etc.. However due to the above mentioned races it is entirely possible for userspace tasks to thaw (by accident) before SMP is back. This can be a fatal problem in asymmetric ISA architectures (eg ARMv9) where the userspace task requires a special CPU to run. As said; replace this with a special task state TASK_FROZEN and add the following state transitions: TASK_FREEZABLE -> TASK_FROZEN __TASK_STOPPED -> TASK_FROZEN __TASK_TRACED -> TASK_FROZEN The new TASK_FREEZABLE can be set on any state part of TASK_NORMAL (IOW. TASK_INTERRUPTIBLE and TASK_UNINTERRUPTIBLE) -- any such state is already required to deal with spurious wakeups and the freezer causes one such when thawing the task (since the original state is lost). The special __TASK_{STOPPED,TRACED} states *can* be restored since their canonical state is in ->jobctl. With this, frozen tasks need an explicit TASK_FROZEN wakeup and are free of undue (early / spurious) wakeups. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Ingo Molnar <[email protected]> Acked-by: Rafael J. Wysocki <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 9963e44 commit f5d39b0

File tree

32 files changed

+210
-395
lines changed

32 files changed

+210
-395
lines changed

drivers/android/binder.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4247,10 +4247,9 @@ static int binder_wait_for_work(struct binder_thread *thread,
42474247
struct binder_proc *proc = thread->proc;
42484248
int ret = 0;
42494249

4250-
freezer_do_not_count();
42514250
binder_inner_proc_lock(proc);
42524251
for (;;) {
4253-
prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE);
4252+
prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE|TASK_FREEZABLE);
42544253
if (binder_has_work_ilocked(thread, do_proc_work))
42554254
break;
42564255
if (do_proc_work)
@@ -4267,7 +4266,6 @@ static int binder_wait_for_work(struct binder_thread *thread,
42674266
}
42684267
finish_wait(&thread->wait, &wait);
42694268
binder_inner_proc_unlock(proc);
4270-
freezer_count();
42714269

42724270
return ret;
42734271
}

drivers/media/pci/pt3/pt3.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ static int pt3_fetch_thread(void *data)
445445
pt3_proc_dma(adap);
446446

447447
delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC);
448-
set_current_state(TASK_UNINTERRUPTIBLE);
449-
freezable_schedule_hrtimeout_range(&delay,
448+
set_current_state(TASK_UNINTERRUPTIBLE|TASK_FREEZABLE);
449+
schedule_hrtimeout_range(&delay,
450450
PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
451451
HRTIMER_MODE_REL);
452452
}

fs/cifs/inode.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,7 +2326,7 @@ cifs_invalidate_mapping(struct inode *inode)
23262326
static int
23272327
cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
23282328
{
2329-
freezable_schedule_unsafe();
2329+
schedule();
23302330
if (signal_pending_state(mode, current))
23312331
return -ERESTARTSYS;
23322332
return 0;
@@ -2344,7 +2344,7 @@ cifs_revalidate_mapping(struct inode *inode)
23442344
return 0;
23452345

23462346
rc = wait_on_bit_lock_action(flags, CIFS_INO_LOCK, cifs_wait_bit_killable,
2347-
TASK_KILLABLE);
2347+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
23482348
if (rc)
23492349
return rc;
23502350

fs/cifs/transport.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -757,8 +757,9 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
757757
{
758758
int error;
759759

760-
error = wait_event_freezekillable_unsafe(server->response_q,
761-
midQ->mid_state != MID_REQUEST_SUBMITTED);
760+
error = wait_event_state(server->response_q,
761+
midQ->mid_state != MID_REQUEST_SUBMITTED,
762+
(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
762763
if (error < 0)
763764
return -ERESTARTSYS;
764765

fs/coredump.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,9 +402,8 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
402402
if (core_waiters > 0) {
403403
struct core_thread *ptr;
404404

405-
freezer_do_not_count();
406-
wait_for_completion(&core_state->startup);
407-
freezer_count();
405+
wait_for_completion_state(&core_state->startup,
406+
TASK_UNINTERRUPTIBLE|TASK_FREEZABLE);
408407
/*
409408
* Wait for all the threads to become inactive, so that
410409
* all the thread context (extended register state, like

fs/nfs/file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,8 @@ static vm_fault_t nfs_vm_page_mkwrite(struct vm_fault *vmf)
570570
}
571571

572572
wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING,
573-
nfs_wait_bit_killable, TASK_KILLABLE);
573+
nfs_wait_bit_killable,
574+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
574575

575576
lock_page(page);
576577
mapping = page_file_mapping(page);

fs/nfs/inode.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,13 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
7272
return nfs_fileid_to_ino_t(fattr->fileid);
7373
}
7474

75-
static int nfs_wait_killable(int mode)
75+
int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
7676
{
77-
freezable_schedule_unsafe();
77+
schedule();
7878
if (signal_pending_state(mode, current))
7979
return -ERESTARTSYS;
8080
return 0;
8181
}
82-
83-
int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
84-
{
85-
return nfs_wait_killable(mode);
86-
}
8782
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
8883

8984
/**
@@ -1331,7 +1326,8 @@ int nfs_clear_invalid_mapping(struct address_space *mapping)
13311326
*/
13321327
for (;;) {
13331328
ret = wait_on_bit_action(bitlock, NFS_INO_INVALIDATING,
1334-
nfs_wait_bit_killable, TASK_KILLABLE);
1329+
nfs_wait_bit_killable,
1330+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
13351331
if (ret)
13361332
goto out;
13371333
spin_lock(&inode->i_lock);

fs/nfs/nfs3proc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
3636
res = rpc_call_sync(clnt, msg, flags);
3737
if (res != -EJUKEBOX)
3838
break;
39-
freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME);
39+
__set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
40+
schedule_timeout(NFS_JUKEBOX_RETRY_TIME);
4041
res = -ERESTARTSYS;
4142
} while (!fatal_signal_pending(current));
4243
return res;

fs/nfs/nfs4proc.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,8 @@ static int nfs4_delay_killable(long *timeout)
416416
{
417417
might_sleep();
418418

419-
freezable_schedule_timeout_killable_unsafe(
420-
nfs4_update_delay(timeout));
419+
__set_current_state(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
420+
schedule_timeout(nfs4_update_delay(timeout));
421421
if (!__fatal_signal_pending(current))
422422
return 0;
423423
return -EINTR;
@@ -427,7 +427,8 @@ static int nfs4_delay_interruptible(long *timeout)
427427
{
428428
might_sleep();
429429

430-
freezable_schedule_timeout_interruptible_unsafe(nfs4_update_delay(timeout));
430+
__set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE_UNSAFE);
431+
schedule_timeout(nfs4_update_delay(timeout));
431432
if (!signal_pending(current))
432433
return 0;
433434
return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
@@ -7406,7 +7407,8 @@ nfs4_retry_setlk_simple(struct nfs4_state *state, int cmd,
74067407
status = nfs4_proc_setlk(state, cmd, request);
74077408
if ((status != -EAGAIN) || IS_SETLK(cmd))
74087409
break;
7409-
freezable_schedule_timeout_interruptible(timeout);
7410+
__set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
7411+
schedule_timeout(timeout);
74107412
timeout *= 2;
74117413
timeout = min_t(unsigned long, NFS4_LOCK_MAXTIMEOUT, timeout);
74127414
status = -ERESTARTSYS;
@@ -7474,10 +7476,8 @@ nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
74747476
break;
74757477

74767478
status = -ERESTARTSYS;
7477-
freezer_do_not_count();
7478-
wait_woken(&waiter.wait, TASK_INTERRUPTIBLE,
7479+
wait_woken(&waiter.wait, TASK_INTERRUPTIBLE|TASK_FREEZABLE,
74797480
NFS4_LOCK_MAXTIMEOUT);
7480-
freezer_count();
74817481
} while (!signalled());
74827482

74837483
remove_wait_queue(q, &waiter.wait);

fs/nfs/nfs4state.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,8 @@ int nfs4_wait_clnt_recover(struct nfs_client *clp)
13141314

13151315
refcount_inc(&clp->cl_count);
13161316
res = wait_on_bit_action(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
1317-
nfs_wait_bit_killable, TASK_KILLABLE);
1317+
nfs_wait_bit_killable,
1318+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
13181319
if (res)
13191320
goto out;
13201321
if (clp->cl_cons_state < 0)

fs/nfs/pnfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,7 +1908,7 @@ static int pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo)
19081908
pnfs_layoutcommit_inode(lo->plh_inode, false);
19091909
return wait_on_bit_action(&lo->plh_flags, NFS_LAYOUT_RETURN,
19101910
nfs_wait_bit_killable,
1911-
TASK_KILLABLE);
1911+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
19121912
}
19131913

19141914
static void nfs_layoutget_begin(struct pnfs_layout_hdr *lo)
@@ -3193,7 +3193,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
31933193
status = wait_on_bit_lock_action(&nfsi->flags,
31943194
NFS_INO_LAYOUTCOMMITTING,
31953195
nfs_wait_bit_killable,
3196-
TASK_KILLABLE);
3196+
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
31973197
if (status)
31983198
goto out;
31993199
}

fs/xfs/xfs_trans_ail.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,9 @@ xfsaild(
602602

603603
while (1) {
604604
if (tout && tout <= 20)
605-
set_current_state(TASK_KILLABLE);
605+
set_current_state(TASK_KILLABLE|TASK_FREEZABLE);
606606
else
607-
set_current_state(TASK_INTERRUPTIBLE);
607+
set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
608608

609609
/*
610610
* Check kthread_should_stop() after we set the task state to
@@ -653,14 +653,14 @@ xfsaild(
653653
ailp->ail_target == ailp->ail_target_prev &&
654654
list_empty(&ailp->ail_buf_list)) {
655655
spin_unlock(&ailp->ail_lock);
656-
freezable_schedule();
656+
schedule();
657657
tout = 0;
658658
continue;
659659
}
660660
spin_unlock(&ailp->ail_lock);
661661

662662
if (tout)
663-
freezable_schedule_timeout(msecs_to_jiffies(tout));
663+
schedule_timeout(msecs_to_jiffies(tout));
664664

665665
__set_current_state(TASK_RUNNING);
666666

0 commit comments

Comments
 (0)