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.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
  79        allow_signal(SIGKILL);
  80        allow_signal(SIGSTOP);
  81        allow_signal(SIGCONT);
  82
  83        c->gc_task = current;
  84        complete(&c->gc_thread_start);
  85
  86        set_user_nice(current, 10);
  87
  88        set_freezable();
  89        for (;;) {
  90                allow_signal(SIGHUP);
  91        again:
  92                spin_lock(&c->erase_completion_lock);
  93                if (!jffs2_thread_should_wake(c)) {
  94                        set_current_state (TASK_INTERRUPTIBLE);
  95                        spin_unlock(&c->erase_completion_lock);
  96                        jffs2_dbg(1, "%s(): sleeping...\n", __func__);
  97                        schedule();
  98                } else
  99                        spin_unlock(&c->erase_completion_lock);
 100                        
 101
 102                /* Problem - immediately after bootup, the GCD spends a lot
 103                 * of time in places like jffs2_kill_fragtree(); so much so
 104                 * that userspace processes (like gdm and X) are starved
 105                 * despite plenty of cond_resched()s and renicing.  Yield()
 106                 * doesn't help, either (presumably because userspace and GCD
 107                 * are generally competing for a higher latency resource -
 108                 * disk).
 109                 * This forces the GCD to slow the hell down.   Pulling an
 110                 * inode in with read_inode() is much preferable to having
 111                 * the GC thread get there first. */
 112                schedule_timeout_interruptible(msecs_to_jiffies(50));
 113
 114                if (kthread_should_stop()) {
 115                        jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
 116                        goto die;
 117                }
 118
 119                /* Put_super will send a SIGKILL and then wait on the sem.
 120                 */
 121                while (signal_pending(current) || freezing(current)) {
 122                        siginfo_t info;
 123                        unsigned long signr;
 124
 125                        if (try_to_freeze())
 126                                goto again;
 127
 128                        signr = dequeue_signal_lock(current, &current->blocked, &info);
 129
 130                        switch(signr) {
 131                        case SIGSTOP:
 132                                jffs2_dbg(1, "%s(): SIGSTOP received\n",
 133                                          __func__);
 134                                set_current_state(TASK_STOPPED);
 135                                schedule();
 136                                break;
 137
 138                        case SIGKILL:
 139                                jffs2_dbg(1, "%s(): SIGKILL received\n",
 140                                          __func__);
 141                                goto die;
 142
 143                        case SIGHUP:
 144                                jffs2_dbg(1, "%s(): SIGHUP received\n",
 145                                          __func__);
 146                                break;
 147                        default:
 148                                jffs2_dbg(1, "%s(): signal %ld received\n",
 149                                          __func__, signr);
 150                        }
 151                }
 152                /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
 153                disallow_signal(SIGHUP);
 154
 155                jffs2_dbg(1, "%s(): pass\n", __func__);
 156                if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
 157                        pr_notice("No space for garbage collection. Aborting GC thread\n");
 158                        goto die;
 159                }
 160        }
 161 die:
 162        spin_lock(&c->erase_completion_lock);
 163        c->gc_task = NULL;
 164        spin_unlock(&c->erase_completion_lock);
 165        complete_and_exit(&c->gc_thread_exit, 0);
 166}
 167
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.