cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

freezer.c (4468B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * kernel/freezer.c - Function to freeze a process
      4 *
      5 * Originally from kernel/power/process.c
      6 */
      7
      8#include <linux/interrupt.h>
      9#include <linux/suspend.h>
     10#include <linux/export.h>
     11#include <linux/syscalls.h>
     12#include <linux/freezer.h>
     13#include <linux/kthread.h>
     14
     15/* total number of freezing conditions in effect */
     16atomic_t system_freezing_cnt = ATOMIC_INIT(0);
     17EXPORT_SYMBOL(system_freezing_cnt);
     18
     19/* indicate whether PM freezing is in effect, protected by
     20 * system_transition_mutex
     21 */
     22bool pm_freezing;
     23bool pm_nosig_freezing;
     24
     25/* protects freezing and frozen transitions */
     26static DEFINE_SPINLOCK(freezer_lock);
     27
     28/**
     29 * freezing_slow_path - slow path for testing whether a task needs to be frozen
     30 * @p: task to be tested
     31 *
     32 * This function is called by freezing() if system_freezing_cnt isn't zero
     33 * and tests whether @p needs to enter and stay in frozen state.  Can be
     34 * called under any context.  The freezers are responsible for ensuring the
     35 * target tasks see the updated state.
     36 */
     37bool freezing_slow_path(struct task_struct *p)
     38{
     39	if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
     40		return false;
     41
     42	if (test_tsk_thread_flag(p, TIF_MEMDIE))
     43		return false;
     44
     45	if (pm_nosig_freezing || cgroup_freezing(p))
     46		return true;
     47
     48	if (pm_freezing && !(p->flags & PF_KTHREAD))
     49		return true;
     50
     51	return false;
     52}
     53EXPORT_SYMBOL(freezing_slow_path);
     54
     55/* Refrigerator is place where frozen processes are stored :-). */
     56bool __refrigerator(bool check_kthr_stop)
     57{
     58	/* Hmm, should we be allowed to suspend when there are realtime
     59	   processes around? */
     60	bool was_frozen = false;
     61	unsigned int save = get_current_state();
     62
     63	pr_debug("%s entered refrigerator\n", current->comm);
     64
     65	for (;;) {
     66		set_current_state(TASK_UNINTERRUPTIBLE);
     67
     68		spin_lock_irq(&freezer_lock);
     69		current->flags |= PF_FROZEN;
     70		if (!freezing(current) ||
     71		    (check_kthr_stop && kthread_should_stop()))
     72			current->flags &= ~PF_FROZEN;
     73		spin_unlock_irq(&freezer_lock);
     74
     75		if (!(current->flags & PF_FROZEN))
     76			break;
     77		was_frozen = true;
     78		schedule();
     79	}
     80
     81	pr_debug("%s left refrigerator\n", current->comm);
     82
     83	/*
     84	 * Restore saved task state before returning.  The mb'd version
     85	 * needs to be used; otherwise, it might silently break
     86	 * synchronization which depends on ordered task state change.
     87	 */
     88	set_current_state(save);
     89
     90	return was_frozen;
     91}
     92EXPORT_SYMBOL(__refrigerator);
     93
     94static void fake_signal_wake_up(struct task_struct *p)
     95{
     96	unsigned long flags;
     97
     98	if (lock_task_sighand(p, &flags)) {
     99		signal_wake_up(p, 0);
    100		unlock_task_sighand(p, &flags);
    101	}
    102}
    103
    104/**
    105 * freeze_task - send a freeze request to given task
    106 * @p: task to send the request to
    107 *
    108 * If @p is freezing, the freeze request is sent either by sending a fake
    109 * signal (if it's not a kernel thread) or waking it up (if it's a kernel
    110 * thread).
    111 *
    112 * RETURNS:
    113 * %false, if @p is not freezing or already frozen; %true, otherwise
    114 */
    115bool freeze_task(struct task_struct *p)
    116{
    117	unsigned long flags;
    118
    119	/*
    120	 * This check can race with freezer_do_not_count, but worst case that
    121	 * will result in an extra wakeup being sent to the task.  It does not
    122	 * race with freezer_count(), the barriers in freezer_count() and
    123	 * freezer_should_skip() ensure that either freezer_count() sees
    124	 * freezing == true in try_to_freeze() and freezes, or
    125	 * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task
    126	 * normally.
    127	 */
    128	if (freezer_should_skip(p))
    129		return false;
    130
    131	spin_lock_irqsave(&freezer_lock, flags);
    132	if (!freezing(p) || frozen(p)) {
    133		spin_unlock_irqrestore(&freezer_lock, flags);
    134		return false;
    135	}
    136
    137	if (!(p->flags & PF_KTHREAD))
    138		fake_signal_wake_up(p);
    139	else
    140		wake_up_state(p, TASK_INTERRUPTIBLE);
    141
    142	spin_unlock_irqrestore(&freezer_lock, flags);
    143	return true;
    144}
    145
    146void __thaw_task(struct task_struct *p)
    147{
    148	unsigned long flags;
    149
    150	spin_lock_irqsave(&freezer_lock, flags);
    151	if (frozen(p))
    152		wake_up_process(p);
    153	spin_unlock_irqrestore(&freezer_lock, flags);
    154}
    155
    156/**
    157 * set_freezable - make %current freezable
    158 *
    159 * Mark %current freezable and enter refrigerator if necessary.
    160 */
    161bool set_freezable(void)
    162{
    163	might_sleep();
    164
    165	/*
    166	 * Modify flags while holding freezer_lock.  This ensures the
    167	 * freezer notices that we aren't frozen yet or the freezing
    168	 * condition is visible to try_to_freeze() below.
    169	 */
    170	spin_lock_irq(&freezer_lock);
    171	current->flags &= ~PF_NOFREEZE;
    172	spin_unlock_irq(&freezer_lock);
    173
    174	return try_to_freeze();
    175}
    176EXPORT_SYMBOL(set_freezable);