18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 58c2ecf20Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/jffs2.h> 178c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 188c2ecf20Sopenharmony_ci#include <linux/completion.h> 198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 208c2ecf20Sopenharmony_ci#include <linux/freezer.h> 218c2ecf20Sopenharmony_ci#include <linux/kthread.h> 228c2ecf20Sopenharmony_ci#include "nodelist.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int jffs2_garbage_collect_thread(void *); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci assert_spin_locked(&c->erase_completion_lock); 308c2ecf20Sopenharmony_ci if (c->gc_task && jffs2_thread_should_wake(c)) 318c2ecf20Sopenharmony_ci send_sig(SIGHUP, c->gc_task, 1); 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* This must only ever be called when no GC thread is currently running */ 358c2ecf20Sopenharmony_ciint jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct task_struct *tsk; 388c2ecf20Sopenharmony_ci int ret = 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci BUG_ON(c->gc_task); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci init_completion(&c->gc_thread_start); 438c2ecf20Sopenharmony_ci init_completion(&c->gc_thread_exit); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index); 468c2ecf20Sopenharmony_ci if (IS_ERR(tsk)) { 478c2ecf20Sopenharmony_ci pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n", 488c2ecf20Sopenharmony_ci -PTR_ERR(tsk)); 498c2ecf20Sopenharmony_ci complete(&c->gc_thread_exit); 508c2ecf20Sopenharmony_ci ret = PTR_ERR(tsk); 518c2ecf20Sopenharmony_ci } else { 528c2ecf20Sopenharmony_ci /* Wait for it... */ 538c2ecf20Sopenharmony_ci jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid); 548c2ecf20Sopenharmony_ci wait_for_completion(&c->gc_thread_start); 558c2ecf20Sopenharmony_ci ret = tsk->pid; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_civoid jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci int wait = 0; 648c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 658c2ecf20Sopenharmony_ci if (c->gc_task) { 668c2ecf20Sopenharmony_ci jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid); 678c2ecf20Sopenharmony_ci send_sig(SIGKILL, c->gc_task, 1); 688c2ecf20Sopenharmony_ci wait = 1; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 718c2ecf20Sopenharmony_ci if (wait) 728c2ecf20Sopenharmony_ci wait_for_completion(&c->gc_thread_exit); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int jffs2_garbage_collect_thread(void *_c) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct jffs2_sb_info *c = _c; 788c2ecf20Sopenharmony_ci sigset_t hupmask; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci siginitset(&hupmask, sigmask(SIGHUP)); 818c2ecf20Sopenharmony_ci allow_signal(SIGKILL); 828c2ecf20Sopenharmony_ci allow_signal(SIGSTOP); 838c2ecf20Sopenharmony_ci allow_signal(SIGHUP); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci c->gc_task = current; 868c2ecf20Sopenharmony_ci complete(&c->gc_thread_start); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci set_user_nice(current, 10); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci set_freezable(); 918c2ecf20Sopenharmony_ci for (;;) { 928c2ecf20Sopenharmony_ci sigprocmask(SIG_UNBLOCK, &hupmask, NULL); 938c2ecf20Sopenharmony_ci again: 948c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 958c2ecf20Sopenharmony_ci if (!jffs2_thread_should_wake(c)) { 968c2ecf20Sopenharmony_ci set_current_state (TASK_INTERRUPTIBLE); 978c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 988c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): sleeping...\n", __func__); 998c2ecf20Sopenharmony_ci schedule(); 1008c2ecf20Sopenharmony_ci } else { 1018c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci /* Problem - immediately after bootup, the GCD spends a lot 1048c2ecf20Sopenharmony_ci * of time in places like jffs2_kill_fragtree(); so much so 1058c2ecf20Sopenharmony_ci * that userspace processes (like gdm and X) are starved 1068c2ecf20Sopenharmony_ci * despite plenty of cond_resched()s and renicing. Yield() 1078c2ecf20Sopenharmony_ci * doesn't help, either (presumably because userspace and GCD 1088c2ecf20Sopenharmony_ci * are generally competing for a higher latency resource - 1098c2ecf20Sopenharmony_ci * disk). 1108c2ecf20Sopenharmony_ci * This forces the GCD to slow the hell down. Pulling an 1118c2ecf20Sopenharmony_ci * inode in with read_inode() is much preferable to having 1128c2ecf20Sopenharmony_ci * the GC thread get there first. */ 1138c2ecf20Sopenharmony_ci schedule_timeout_interruptible(msecs_to_jiffies(50)); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (kthread_should_stop()) { 1168c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__); 1178c2ecf20Sopenharmony_ci goto die; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Put_super will send a SIGKILL and then wait on the sem. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci while (signal_pending(current) || freezing(current)) { 1238c2ecf20Sopenharmony_ci unsigned long signr; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (try_to_freeze()) 1268c2ecf20Sopenharmony_ci goto again; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci signr = kernel_dequeue_signal(); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch(signr) { 1318c2ecf20Sopenharmony_ci case SIGSTOP: 1328c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): SIGSTOP received\n", 1338c2ecf20Sopenharmony_ci __func__); 1348c2ecf20Sopenharmony_ci kernel_signal_stop(); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci case SIGKILL: 1388c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): SIGKILL received\n", 1398c2ecf20Sopenharmony_ci __func__); 1408c2ecf20Sopenharmony_ci goto die; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci case SIGHUP: 1438c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): SIGHUP received\n", 1448c2ecf20Sopenharmony_ci __func__); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci default: 1478c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): signal %ld received\n", 1488c2ecf20Sopenharmony_ci __func__, signr); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ 1528c2ecf20Sopenharmony_ci sigprocmask(SIG_BLOCK, &hupmask, NULL); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci jffs2_dbg(1, "%s(): pass\n", __func__); 1558c2ecf20Sopenharmony_ci if (jffs2_garbage_collect_pass(c) == -ENOSPC) { 1568c2ecf20Sopenharmony_ci pr_notice("No space for garbage collection. Aborting GC thread\n"); 1578c2ecf20Sopenharmony_ci goto die; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci die: 1618c2ecf20Sopenharmony_ci spin_lock(&c->erase_completion_lock); 1628c2ecf20Sopenharmony_ci c->gc_task = NULL; 1638c2ecf20Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 1648c2ecf20Sopenharmony_ci complete_and_exit(&c->gc_thread_exit, 0); 1658c2ecf20Sopenharmony_ci} 166