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