linux/fs/jffs2/background.c
<<
>>
Prefs
   1/*
   2 * JFFS2 -- Journalling Flash File System, Version 2.
   3 *
   4 * Copyright © 2001-2007 Red Hat, Inc.
   5 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
   6 *
   7 * Created by David Woodhouse <dwmw2@infradead.org>
   8 *
   9 * For licensing information, see the file 'LICENCE' in this directory.
  10 *
  11 */
  12
  13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14
  15#include <linux/kernel.h>
  16#include <linux/jffs2.h>
  17#include <linux/mtd/mtd.h>
  18#include <linux/completion.h>
  19#include <linux/sched/signal.h>
  20#include <linux/freezer.h>
  21#include <linux/kthread.h>
  22#include "nodelist.h"
  23
  24
  25static int jffs2_garbage_collect_thread(void *);
  26
  27void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
  28{
  29        assert_spin_locked(&c->erase_completion_lock);
  30        if (c->gc_task && jffs2_thread_should_wake(c))
  31                send_sig(SIGHUP, c->gc_task, 1);
  32}
  33
  34/* This must only ever be called when no GC thread is currently running */
  35int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
  36{
  37        struct task_struct *tsk;
  38        int ret = 0;
  39
  40        BUG_ON(c->gc_task);
  41
  42        init_completion(&c->gc_thread_start);
  43        init_completion(&c->gc_thread_exit);
  44
  45        tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index);
  46        if (IS_ERR(tsk)) {
  47                pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n",
  48                        -PTR_ERR(tsk));
  49                complete(&c->gc_thread_exit);
  50                ret = PTR_ERR(tsk);
  51        } else {
  52                /* Wait for it... */
  53                jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid);
  54                wait_for_completion(&c->gc_thread_start);
  55                ret = tsk->pid;
  56        }
  57
  58        return ret;
  59}
  60
  61void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
  62{
  63        int wait = 0;
  64        spin_lock(&c->erase_completion_lock);
  65        if (c->gc_task) {
  66                jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid);
  67                send_sig(SIGKILL, c->gc_task, 1);
  68                wait = 1;
  69        }
  70        spin_unlock(&c->erase_completion_lock);
  71        if (wait)
  72                wait_for_completion(&c->gc_thread_exit);
  73}
  74
  75static int jffs2_garbage_collect_thread(void *_c)
  76{
  77        struct jffs2_sb_info *c = _c;
  78        sigset_t hupmask;
  79
  80        siginitset(&hupmask, sigmask(SIGHUP));
  81        allow_signal(SIGKILL);
  82        allow_signal(SIGSTOP);
  83        allow_signal(SIGHUP);
  84
  85        c->gc_task = current;
  86        complete(&c->gc_thread_start);
  87
  88        set_user_nice(current, 10);
  89
  90        set_freezable();
  91        for (;;) {
  92                sigprocmask(SIG_UNBLOCK, &hupmask, NULL);
  93        again:
  94                spin_lock(&c->erase_completion_lock);
  95                if (!jffs2_thread_should_wake(c)) {
  96                        set_current_state (TASK_INTERRUPTIBLE);
  97                        spin_unlock(&c->erase_completion_lock);
  98                        jffs2_dbg(1, "%s(): sleeping...\n", __func__);
  99                        schedule();
 100                } else {
 101                        spin_unlock(&c->erase_completion_lock);
 102                }
 103                /* Problem - immediately after bootup, the GCD spends a lot
 104                 * of time in places like jffs2_kill_fragtree(); so much so
 105                 * that userspace processes (like gdm and X) are starved
 106                 * despite plenty of cond_resched()s and renicing.  Yield()
 107                 * doesn't help, either (presumably because userspace and GCD
 108                 * are generally competing for a higher latency resource -
 109                 * disk).
 110                 * This forces the GCD to slow the hell down.   Pulling an
 111                 * inode in with read_inode() is much preferable to having
 112                 * the GC thread get there first. */
 113                schedule_timeout_interruptible(msecs_to_jiffies(50));
 114
 115                if (kthread_should_stop()) {
 116                        jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
 117                        goto die;
 118                }
 119
 120                /* Put_super will send a SIGKILL and then wait on the sem.
 121                 */
 122                while (signal_pending(current) || freezing(current)) {
 123                        unsigned long signr;
 124
 125                        if (try_to_freeze())
 126                                goto again;
 127
 128                        signr = kernel_dequeue_signal();
 129
 130                        switch(signr) {
 131                        case SIGSTOP:
 132                                jffs2_dbg(1, "%s(): SIGSTOP received\n",
 133                                          __func__);
 134                                kernel_signal_stop();
 135                                break;
 136
 137                        case SIGKILL:
 138                                jffs2_dbg(1, "%s(): SIGKILL received\n",
 139                                          __func__);
 140                                goto die;
 141
 142                        case SIGHUP:
 143                                jffs2_dbg(1, "%s(): SIGHUP received\n",
 144                                          __func__);
 145                                break;
 146                        default:
 147                                jffs2_dbg(1, "%s(): signal %ld received\n",
 148                                          __func__, signr);
 149                        }
 150                }
 151                /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
 152                sigprocmask(SIG_BLOCK, &hupmask, NULL);
 153
 154                jffs2_dbg(1, "%s(): pass\n", __func__);
 155                if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
 156                        pr_notice("No space for garbage collection. Aborting GC thread\n");
 157                        goto die;
 158                }
 159        }
 160 die:
 161        spin_lock(&c->erase_completion_lock);
 162        c->gc_task = NULL;
 163        spin_unlock(&c->erase_completion_lock);
 164        complete_and_exit(&c->gc_thread_exit, 0);
 165}
 166