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