This patch * Provides an interface to selectively freeze the system for different events. * Allows tasks to exempt themselves or other tasks from specific freeze events. * Allow nesting of freezer calls. For eg:
freeze_processes(EVENT_A); /* Do something with respect to event A */ . . . freeze_processes(EVENT_B); /* Do something with respect to event B */ . . . thaw_processes(EVENT_B); . . . thaw_processes(EVENT_B); This type of behaviour would be required when cpu hotplug would start using the process freezer, where EVENT_A would be SUSPEND and EVENT_B would be HOTPLUG_CPU. This patch applies on the top of 2.6.21-rc7-mm2 + Rafael's freezer changes from http://lkml.org/lkml/2007/4/27/302. Signed-off-by: Gautham R Shenoy <[EMAIL PROTECTED]> --- arch/i386/kernel/apm.c | 2 - drivers/block/loop.c | 2 - drivers/char/apm-emulation.c | 6 +-- drivers/ieee1394/ieee1394_core.c | 2 - drivers/md/md.c | 2 - drivers/mmc/card/queue.c | 2 - drivers/mtd/mtd_blkdevs.c | 2 - drivers/scsi/libsas/sas_scsi_host.c | 2 - drivers/scsi/scsi_error.c | 2 - drivers/usb/storage/usb.c | 2 - include/linux/freezer.h | 44 +++++++++++++++++++----- kernel/freezer.c | 64 ++++++++++++++++++++++++++++++------ kernel/kprobes.c | 4 +- kernel/kthread.c | 2 - kernel/power/disk.c | 4 +- kernel/power/main.c | 8 ++-- kernel/power/user.c | 6 +-- kernel/rcutorture.c | 4 +- kernel/sched.c | 2 - kernel/softirq.c | 2 - kernel/softlockup.c | 2 - kernel/workqueue.c | 2 - 22 files changed, 119 insertions(+), 49 deletions(-) Index: linux-2.6.21-rc7/include/linux/freezer.h =================================================================== --- linux-2.6.21-rc7.orig/include/linux/freezer.h +++ linux-2.6.21-rc7/include/linux/freezer.h @@ -4,17 +4,27 @@ #ifdef CONFIG_FREEZER + /* * Per task flags used by the freezer * * They should not be referred to directly outside of this file. */ -#define TFF_NOFREEZE 0 /* task should not be frozen */ +#define TFF_FE_SUSPEND 0 /* Do not freeze task for software suspend */ +#define TFF_FE_KPROBES 1 /* Do not freeze task for kprobes */ #define TFF_FREEZE 8 /* task should go to the refrigerator ASAP */ #define TFF_SKIP 9 /* do not count this task as freezable */ #define TFF_FROZEN 10 /* task is frozen */ /* + * Codes of different events which use the freezer + * These are the only flags that can be referred outside this file + */ +#define FE_SUSPEND (1 << TFF_FE_SUSPEND) /* Software Suspend */ +#define FE_KPROBES (1 << TFF_FE_KPROBES) /* Kprobes */ +#define FE_ALL (FE_SUSPEND | FE_KPROBES) /* All events using freezer */ + +/* * Check if a process has been frozen */ static inline int frozen(struct task_struct *p) @@ -57,19 +67,29 @@ static inline void clear_freeze_flag(str } /* - * Check if the task wants to be exempted from freezing + * Check if the task wants to be exempted from freezing for + * freeze_event. */ -static inline int freezer_should_exempt(struct task_struct *p) +static inline int freezer_should_exempt(struct task_struct *p, + unsigned long freeze_event) { - return test_bit(TFF_NOFREEZE, &p->freezer_flags); + return p->freezer_flags & freeze_event; } /* * Tell the freezer to exempt this task from freezing + * for events in freeze_event_mask. */ -static inline void freezer_exempt(struct task_struct *p) +static inline void freezer_exempt(struct task_struct *p, + unsigned long freeze_event_mask) +{ + atomic_set_mask(freeze_event_mask, &p->freezer_flags); +} + +/* Returns the mask of the events for which this process is freezeable */ +static inline unsigned long freezeable_event_mask(struct task_struct *p) { - set_bit(TFF_NOFREEZE, &p->freezer_flags); + return ~p->freezer_flags & FE_ALL; } /* @@ -96,8 +116,8 @@ static inline int thaw_process(struct ta } extern void refrigerator(void); -extern int freeze_processes(void); -extern void thaw_processes(void); +extern int freeze_processes(unsigned long freeze_event); +extern void thaw_processes(unsigned long freeze_event); static inline int try_to_freeze(void) { @@ -160,11 +180,15 @@ static inline int freezing(struct task_s static inline void freeze(struct task_struct *p) { BUG(); } static inline int freezer_should_exempt(struct task_struct *p) { return 0; } static inline void freezer_exempt(struct task_struct *p) {} +static inline unsigned long freezeable_event_mask(struct task_struct *p) +{ + return 0; +} static inline int thaw_process(struct task_struct *p) { return 1; } static inline void refrigerator(void) {} -static inline int freeze_processes(void) { BUG(); return 0; } -static inline void thaw_processes(void) {} +static inline int freeze_processes(unsigned long) { BUG(); return 0; } +static inline void thaw_processes(unsigned long) {} static inline int try_to_freeze(void) { return 0; } Index: linux-2.6.21-rc7/kernel/freezer.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/freezer.c +++ linux-2.6.21-rc7/kernel/freezer.c @@ -23,21 +23,44 @@ #define FREEZER_KERNEL_THREADS 0 #define FREEZER_USER_SPACE 1 +static DEFINE_MUTEX(freezer_mutex); +/* Mask of the events for which the system is currently frozen */ +unsigned long system_frozen_event_mask; +/* The event for which the freeze request has been raised */ +unsigned long current_freezer_event; + static inline int freezeable(struct task_struct * p) { if ((p == current) || - freezer_should_exempt(p) || + freezer_should_exempt(p, current_freezer_event) || (p->exit_state != 0)) return 0; return 1; } +/* Returns the mask of events for which p is currently frozen */ +static inline unsigned long process_frozen_event_mask(struct task_struct *p) +{ + return (freezeable_event_mask(p) & system_frozen_event_mask); +} + +static inline int thawable(struct task_struct *p) +{ + if (!freezeable(p)) + return 0; + + /* Thaw p iff it is frozen for current_freezer_event alone */ + if (process_frozen_event_mask(p) & ~current_freezer_event) + return 0; + + return 1; +} /* * freezing is complete, mark current process as frozen */ static inline void frozen_process(void) { - if (!unlikely(freezer_should_exempt(current))) { + if (!unlikely(freezer_should_exempt(current, current_freezer_event))) { set_frozen_flag(current); wmb(); } @@ -185,26 +208,39 @@ static unsigned int try_to_freeze_tasks( /** * freeze_processes - tell processes to enter the refrigerator * + * @freeze_event : Event that's requesting the services + * of the process freezer to freeze the system + * * Returns 0 on success, or the number of processes that didn't freeze, * although they were told to. */ -int freeze_processes(void) +int freeze_processes(unsigned long freeze_event) { - unsigned int nr_unfrozen; + unsigned int nr_unfrozen = 0; + + mutex_lock(&freezer_mutex); + if (system_frozen_event_mask & freeze_event) + goto out; + + current_freezer_event = freeze_event; printk("Stopping tasks ... "); nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE); if (nr_unfrozen) - return nr_unfrozen; + goto out; sys_sync(); nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS); if (nr_unfrozen) - return nr_unfrozen; + goto out; + system_frozen_event_mask |= current_freezer_event; printk("done.\n"); BUG_ON(in_atomic()); - return 0; +out: + current_freezer_event = 0; + mutex_unlock(&freezer_mutex); + return nr_unfrozen; } static void thaw_tasks(int thaw_user_space) @@ -213,7 +249,7 @@ static void thaw_tasks(int thaw_user_spa read_lock(&tasklist_lock); do_each_thread(g, p) { - if (!freezeable(p)) + if (!thawable(p)) continue; if (is_user_space(p) == !thaw_user_space) @@ -224,13 +260,23 @@ static void thaw_tasks(int thaw_user_spa read_unlock(&tasklist_lock); } -void thaw_processes(void) +void thaw_processes(unsigned long thaw_event) { + mutex_lock(&freezer_mutex); + if (!(system_frozen_event_mask & thaw_event)) { + WARN_ON(1); + goto out; + } + current_freezer_event = thaw_event; printk("Restarting tasks ... "); thaw_tasks(FREEZER_KERNEL_THREADS); thaw_tasks(FREEZER_USER_SPACE); + system_frozen_event_mask &= ~current_freezer_event; schedule(); printk("done.\n"); +out: + current_freezer_event = 0; + mutex_unlock(&freezer_mutex); } EXPORT_SYMBOL(refrigerator); Index: linux-2.6.21-rc7/arch/i386/kernel/apm.c =================================================================== --- linux-2.6.21-rc7.orig/arch/i386/kernel/apm.c +++ linux-2.6.21-rc7/arch/i386/kernel/apm.c @@ -2313,7 +2313,7 @@ static int __init apm_init(void) remove_proc_entry("apm", NULL); return err; } - freezer_exempt(kapmd_task); + freezer_exempt(kapmd_task, FE_ALL); wake_up_process(kapmd_task); if (num_online_cpus() > 1 && !smp ) { Index: linux-2.6.21-rc7/drivers/block/loop.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/block/loop.c +++ linux-2.6.21-rc7/drivers/block/loop.c @@ -582,7 +582,7 @@ static int loop_thread(void *data) * hence, it mustn't be stopped at all * because it could be indirectly used during suspension */ - freezer_exempt(current); + freezer_exempt(current, FE_ALL); set_user_nice(current, -20); Index: linux-2.6.21-rc7/drivers/char/apm-emulation.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/char/apm-emulation.c +++ linux-2.6.21-rc7/drivers/char/apm-emulation.c @@ -336,7 +336,7 @@ apm_ioctl(struct inode * inode, struct f * threads. */ flags = current->flags; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); wait_event(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); @@ -372,7 +372,7 @@ apm_ioctl(struct inode * inode, struct f * threads. */ flags = current->flags; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); wait_event_interruptible(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); @@ -601,7 +601,7 @@ static int __init apm_init(void) kapmd_tsk = NULL; return ret; } - freezer_exempt(kapmd_tsk); + freezer_exempt(kapmd_tsk, FE_ALL); wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS Index: linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/ieee1394/ieee1394_core.c +++ linux-2.6.21-rc7/drivers/ieee1394/ieee1394_core.c @@ -1134,7 +1134,7 @@ static int hpsbpkt_thread(void *__hi) struct list_head tmp; int may_schedule; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); while (!kthread_should_stop()) { Index: linux-2.6.21-rc7/drivers/md/md.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/md/md.c +++ linux-2.6.21-rc7/drivers/md/md.c @@ -4541,7 +4541,7 @@ static int md_thread(void * arg) * many dirty RAID5 blocks. */ - freezer_exempt(current); + freezer_exempt(current, FE_ALL); while (!kthread_should_stop()) { /* We need to wait INTERRUPTIBLE so that Index: linux-2.6.21-rc7/drivers/mmc/card/queue.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/mmc/card/queue.c +++ linux-2.6.21-rc7/drivers/mmc/card/queue.c @@ -67,7 +67,7 @@ static int mmc_queue_thread(void *d) * the process freezing. We handle suspension ourselves. */ current->flags |= PF_MEMALLOC; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); down(&mq->thread_sem); do { Index: linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/mtd/mtd_blkdevs.c +++ linux-2.6.21-rc7/drivers/mtd/mtd_blkdevs.c @@ -82,7 +82,7 @@ static int mtd_blktrans_thread(void *arg /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); spin_lock_irq(rq->queue_lock); while (!kthread_should_stop()) { Index: linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/scsi/libsas/sas_scsi_host.c +++ linux-2.6.21-rc7/drivers/scsi/libsas/sas_scsi_host.c @@ -871,7 +871,7 @@ static int sas_queue_thread(void *_sas_h struct sas_ha_struct *sas_ha = _sas_ha; struct scsi_core *core = &sas_ha->core; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); complete(&queue_th_comp); Index: linux-2.6.21-rc7/drivers/scsi/scsi_error.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/scsi/scsi_error.c +++ linux-2.6.21-rc7/drivers/scsi/scsi_error.c @@ -1536,7 +1536,7 @@ int scsi_error_handler(void *data) { struct Scsi_Host *shost = data; - freezer_exempt(current); + freezer_exempt(current, FE_ALL); /* * We use TASK_INTERRUPTIBLE so that the thread is not Index: linux-2.6.21-rc7/drivers/usb/storage/usb.c =================================================================== --- linux-2.6.21-rc7.orig/drivers/usb/storage/usb.c +++ linux-2.6.21-rc7/drivers/usb/storage/usb.c @@ -301,7 +301,7 @@ static int usb_stor_control_thread(void struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); for(;;) { try_to_freeze(); Index: linux-2.6.21-rc7/kernel/kthread.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/kthread.c +++ linux-2.6.21-rc7/kernel/kthread.c @@ -233,7 +233,7 @@ int kthreadd(void *unused) /* Setup a clean context for our children to inherit. */ kthreadd_setup(); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); for (;;) { set_current_state(TASK_INTERRUPTIBLE); Index: linux-2.6.21-rc7/kernel/rcutorture.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/rcutorture.c +++ linux-2.6.21-rc7/kernel/rcutorture.c @@ -559,7 +559,7 @@ rcu_torture_fakewriter(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started"); set_user_nice(current, 19); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); do { schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); @@ -590,7 +590,7 @@ rcu_torture_reader(void *arg) VERBOSE_PRINTK_STRING("rcu_torture_reader task started"); set_user_nice(current, 19); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); do { idx = cur_ops->readlock(); Index: linux-2.6.21-rc7/kernel/sched.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/sched.c +++ linux-2.6.21-rc7/kernel/sched.c @@ -5478,7 +5478,7 @@ migration_call(struct notifier_block *nf p = kthread_create(migration_thread, hcpu, "migration/%d",cpu); if (IS_ERR(p)) return NOTIFY_BAD; - freezer_exempt(p); + freezer_exempt(p, FE_ALL); kthread_bind(p, cpu); /* Must be high prio: stop_machine expects to yield to it. */ rq = task_rq_lock(p, &flags); Index: linux-2.6.21-rc7/kernel/softirq.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/softirq.c +++ linux-2.6.21-rc7/kernel/softirq.c @@ -490,7 +490,7 @@ void __init softirq_init(void) static int ksoftirqd(void * __bind_cpu) { set_user_nice(current, 15); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); set_current_state(TASK_INTERRUPTIBLE); Index: linux-2.6.21-rc7/kernel/softlockup.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/softlockup.c +++ linux-2.6.21-rc7/kernel/softlockup.c @@ -117,7 +117,7 @@ static int watchdog(void * __bind_cpu) struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; sched_setscheduler(current, SCHED_FIFO, ¶m); - freezer_exempt(current); + freezer_exempt(current, FE_ALL); /* initialize timestamp */ touch_softlockup_watchdog(); Index: linux-2.6.21-rc7/kernel/workqueue.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/workqueue.c +++ linux-2.6.21-rc7/kernel/workqueue.c @@ -291,7 +291,7 @@ static int worker_thread(void *__cwq) DEFINE_WAIT(wait); if (!cwq->wq->freezeable) - freezer_exempt(current); + freezer_exempt(current, FE_ALL); for (;;) { prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE); Index: linux-2.6.21-rc7/kernel/kprobes.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/kprobes.c +++ linux-2.6.21-rc7/kernel/kprobes.c @@ -109,7 +109,7 @@ static int __kprobes check_safety(void) { int ret = 0; #ifdef CONFIG_PREEMPT - ret = freeze_processes(); + ret = freeze_processes(FE_KPROBES); if (ret == 0) { struct task_struct *p, *q; do_each_thread(p, q) { @@ -122,7 +122,7 @@ static int __kprobes check_safety(void) } while_each_thread(p, q); } loop_end: - thaw_processes(); + thaw_processes(FE_KPROBES); #else synchronize_sched(); #endif Index: linux-2.6.21-rc7/kernel/power/disk.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/power/disk.c +++ linux-2.6.21-rc7/kernel/power/disk.c @@ -103,7 +103,7 @@ static inline void platform_finish(void) static void unprepare_processes(void) { - thaw_processes(); + thaw_processes(FE_SUSPEND); pm_restore_console(); } @@ -112,7 +112,7 @@ static int prepare_processes(void) int error = 0; pm_prepare_console(); - if (freeze_processes()) { + if (freeze_processes(FE_SUSPEND)) { error = -EBUSY; unprepare_processes(); } Index: linux-2.6.21-rc7/kernel/power/main.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/power/main.c +++ linux-2.6.21-rc7/kernel/power/main.c @@ -90,9 +90,9 @@ static int suspend_prepare(suspend_state if (error) goto Finish; - if (freeze_processes()) { + if (freeze_processes(FE_SUSPEND)) { error = -EAGAIN; - thaw_processes(); + thaw_processes(FE_SUSPEND); goto Finish; } @@ -133,7 +133,7 @@ static int suspend_prepare(suspend_state resume_console(); Thaw: suspend_notifier_call_chain(SUSPEND_THAW_PREPARE); - thaw_processes(); + thaw_processes(FE_SUSPEND); Finish: pm_restore_console(); suspend_notifier_call_chain(SUSPEND_FINISHED); @@ -185,7 +185,7 @@ static void suspend_finish(suspend_state device_resume(); resume_console(); suspend_notifier_call_chain(SUSPEND_THAW_PREPARE); - thaw_processes(); + thaw_processes(FE_SUSPEND); pm_restore_console(); suspend_notifier_call_chain(SUSPEND_FINISHED); } Index: linux-2.6.21-rc7/kernel/power/user.c =================================================================== --- linux-2.6.21-rc7.orig/kernel/power/user.c +++ linux-2.6.21-rc7/kernel/power/user.c @@ -81,7 +81,7 @@ static void snapshot_unfreeze(struct sna return; mutex_lock(&pm_mutex); - thaw_processes(); + thaw_processes(FE_SUSPEND); suspend_notifier_call_chain(SUSPEND_FINISHED); mutex_unlock(&pm_mutex); data->frozen = 0; @@ -257,8 +257,8 @@ static int snapshot_ioctl(struct inode * if (error) break; - if (freeze_processes()) { - thaw_processes(); + if (freeze_processes(FE_SUSPEND)) { + thaw_processes(FE_SUSPEND); suspend_notifier_call_chain(SUSPEND_FINISHED); error = -EBUSY; } -- Gautham R Shenoy Linux Technology Center IBM India. "Freedom comes with a price tag of responsibility, which is still a bargain, because Freedom is priceless!" - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/