2005-04-17 02:20:36 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2001 - 2007 Red Hat , Inc .
2010-08-08 17:15:22 +04:00
* Copyright © 2004 - 2010 David Woodhouse < dwmw2 @ infradead . org >
2005-04-17 02:20:36 +04:00
*
* Created by David Woodhouse < dwmw2 @ infradead . org >
*
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
2012-02-16 03:56:45 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/jffs2.h>
# include <linux/mtd/mtd.h>
# include <linux/completion.h>
2017-02-08 20:51:30 +03:00
# include <linux/sched/signal.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2009-06-18 00:08:55 +04:00
# include <linux/kthread.h>
2005-04-17 02:20:36 +04:00
# include "nodelist.h"
static int jffs2_garbage_collect_thread ( void * ) ;
void jffs2_garbage_collect_trigger ( struct jffs2_sb_info * c )
{
2010-05-19 20:00:10 +04:00
assert_spin_locked ( & c - > erase_completion_lock ) ;
2007-07-10 13:01:22 +04:00
if ( c - > gc_task & & jffs2_thread_should_wake ( c ) )
send_sig ( SIGHUP , c - > gc_task , 1 ) ;
2005-04-17 02:20:36 +04:00
}
/* This must only ever be called when no GC thread is currently running */
int jffs2_start_garbage_collect_thread ( struct jffs2_sb_info * c )
{
2009-06-18 00:08:55 +04:00
struct task_struct * tsk ;
2005-04-17 02:20:36 +04:00
int ret = 0 ;
2006-04-01 03:15:35 +04:00
BUG_ON ( c - > gc_task ) ;
2005-04-17 02:20:36 +04:00
2005-05-19 20:18:11 +04:00
init_completion ( & c - > gc_thread_start ) ;
2005-04-17 02:20:36 +04:00
init_completion ( & c - > gc_thread_exit ) ;
2009-06-18 00:08:55 +04:00
tsk = kthread_run ( jffs2_garbage_collect_thread , c , " jffs2_gcd_mtd%d " , c - > mtd - > index ) ;
if ( IS_ERR ( tsk ) ) {
2012-02-16 03:56:44 +04:00
pr_warn ( " fork failed for JFFS2 garbage collect thread: %ld \n " ,
- PTR_ERR ( tsk ) ) ;
2005-04-17 02:20:36 +04:00
complete ( & c - > gc_thread_exit ) ;
2009-06-18 00:08:55 +04:00
ret = PTR_ERR ( tsk ) ;
2005-04-17 02:20:36 +04:00
} else {
/* Wait for it... */
2012-02-16 03:56:45 +04:00
jffs2_dbg ( 1 , " Garbage collect thread is pid %d \n " , tsk - > pid ) ;
2005-05-19 20:18:11 +04:00
wait_for_completion ( & c - > gc_thread_start ) ;
2009-06-18 00:08:55 +04:00
ret = tsk - > pid ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_stop_garbage_collect_thread ( struct jffs2_sb_info * c )
{
2005-05-21 01:37:15 +04:00
int wait = 0 ;
2005-04-17 02:20:36 +04:00
spin_lock ( & c - > erase_completion_lock ) ;
if ( c - > gc_task ) {
2012-02-16 03:56:45 +04:00
jffs2_dbg ( 1 , " Killing GC task %d \n " , c - > gc_task - > pid ) ;
2005-04-17 02:20:36 +04:00
send_sig ( SIGKILL , c - > gc_task , 1 ) ;
2005-05-21 01:37:15 +04:00
wait = 1 ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & c - > erase_completion_lock ) ;
2005-05-21 01:37:15 +04:00
if ( wait )
wait_for_completion ( & c - > gc_thread_exit ) ;
2005-04-17 02:20:36 +04:00
}
static int jffs2_garbage_collect_thread ( void * _c )
{
struct jffs2_sb_info * c = _c ;
2014-06-07 01:36:55 +04:00
sigset_t hupmask ;
2005-04-17 02:20:36 +04:00
2014-06-07 01:36:55 +04:00
siginitset ( & hupmask , sigmask ( SIGHUP ) ) ;
2005-04-17 02:20:36 +04:00
allow_signal ( SIGKILL ) ;
allow_signal ( SIGSTOP ) ;
2014-06-07 01:36:55 +04:00
allow_signal ( SIGHUP ) ;
2005-04-17 02:20:36 +04:00
c - > gc_task = current ;
2005-05-19 20:18:11 +04:00
complete ( & c - > gc_thread_start ) ;
2005-04-17 02:20:36 +04:00
set_user_nice ( current , 10 ) ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2005-04-17 02:20:36 +04:00
for ( ; ; ) {
2014-06-07 01:36:55 +04:00
sigprocmask ( SIG_UNBLOCK , & hupmask , NULL ) ;
2007-06-28 22:49:36 +04:00
again :
2008-10-31 17:52:24 +03:00
spin_lock ( & c - > erase_completion_lock ) ;
2005-04-17 02:20:36 +04:00
if ( ! jffs2_thread_should_wake ( c ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
2008-10-31 17:52:24 +03:00
spin_unlock ( & c - > erase_completion_lock ) ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): sleeping... \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
schedule ( ) ;
2014-06-07 01:36:55 +04:00
} else {
2008-10-31 17:52:24 +03:00
spin_unlock ( & c - > erase_completion_lock ) ;
2014-06-07 01:36:55 +04:00
}
2009-02-12 00:27:02 +03:00
/* Problem - immediately after bootup, the GCD spends a lot
* of time in places like jffs2_kill_fragtree ( ) ; so much so
* that userspace processes ( like gdm and X ) are starved
* despite plenty of cond_resched ( ) s and renicing . Yield ( )
* doesn ' t help , either ( presumably because userspace and GCD
* are generally competing for a higher latency resource -
* disk ) .
* This forces the GCD to slow the hell down . Pulling an
* inode in with read_inode ( ) is much preferable to having
* the GC thread get there first . */
schedule_timeout_interruptible ( msecs_to_jiffies ( 50 ) ) ;
2005-04-17 02:20:36 +04:00
2009-06-18 00:08:55 +04:00
if ( kthread_should_stop ( ) ) {
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): kthread_stop() called \n " , __func__ ) ;
2009-06-18 00:08:55 +04:00
goto die ;
}
2005-11-07 14:16:07 +03:00
/* Put_super will send a SIGKILL and then wait on the sem.
2005-04-17 02:20:36 +04:00
*/
2007-12-04 03:11:09 +03:00
while ( signal_pending ( current ) | | freezing ( current ) ) {
2005-04-17 02:20:36 +04:00
unsigned long signr ;
2007-06-28 22:49:36 +04:00
if ( try_to_freeze ( ) )
goto again ;
2018-07-20 05:31:13 +03:00
signr = kernel_dequeue_signal ( ) ;
2005-04-17 02:20:36 +04:00
switch ( signr ) {
case SIGSTOP :
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): SIGSTOP received \n " ,
__func__ ) ;
2015-11-07 03:32:25 +03:00
kernel_signal_stop ( ) ;
2005-04-17 02:20:36 +04:00
break ;
case SIGKILL :
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): SIGKILL received \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
goto die ;
case SIGHUP :
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): SIGHUP received \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): signal %ld received \n " ,
__func__ , signr ) ;
2005-04-17 02:20:36 +04:00
}
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
2014-06-07 01:36:55 +04:00
sigprocmask ( SIG_BLOCK , & hupmask , NULL ) ;
2005-04-17 02:20:36 +04:00
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): pass \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( jffs2_garbage_collect_pass ( c ) = = - ENOSPC ) {
2012-02-16 03:56:44 +04:00
pr_notice ( " No space for garbage collection. Aborting GC thread \n " ) ;
2005-04-17 02:20:36 +04:00
goto die ;
}
}
die :
spin_lock ( & c - > erase_completion_lock ) ;
c - > gc_task = NULL ;
spin_unlock ( & c - > erase_completion_lock ) ;
2021-11-22 20:15:19 +03:00
kthread_complete_and_exit ( & c - > gc_thread_exit , 0 ) ;
2005-04-17 02:20:36 +04:00
}