linux/fs/jffs2/background.c
<<
>>
Prefs
   1/*
   2 * JFFS2 -- Journalling Flash File System, Version 2.
   3 *
   4 * Copyright \xC2\xA9 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 "nodelist.h"
  19
  20
  21static int jffs2_garbage_collect_thread(void *);
  22
  23void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
  24{
  25        spin_lock(&c->erase_completion_lock);
  26        if (c->gc_task && jffs2_thread_should_wake(c))
  27                send_sig(SIGHUP, c->gc_task, 1);
  28        spin_unlock(&c->erase_completion_lock);
  29}
  30
  31/* This must only ever be called when no GC thread is currently running */
  32int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
  33{
  34        pid_t pid;
  35        int ret = 0;
  36
  37        BUG_ON(c->gc_task);
  38
  39        init_completion(&c->gc_thread_start);
  40        init_completion(&c->gc_thread_exit);
  41
  42        pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES);
  43        if (pid < 0) {
  44                printk(KERN_WARNING "fork failed for JFFS2 garbage collect thread: %d\n", -pid);
  45                complete(&c->gc_thread_exit);
  46                ret = pid;
  47        } else {
  48                /* Wait for it... */
  49                D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid));
  50                wait_for_completion(&c->gc_thread_start);
  51        }
  52
  53        return ret;
  54}
  55
  56void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
  57{
  58        int wait = 0;
  59        spin_lock(&c->erase_completion_lock);
  60        if (c->gc_task) {
  61                D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
  62                send_sig(SIGKILL, c->gc_task, 1);
  63                wait = 1;
  64        }
  65        spin_unlock(&c->erase_completion_lock);
  66        if (wait)
  67                wait_for_completion(&c->gc_thread_exit);
  68}
  69
  70static int jffs2_garbage_collect_thread(void *_c)
  71{
  72        struct jffs2_sb_info *c = _c;
  73
  74        daemonize("jffs2_gcd_mtd%d", c->mtd->index);
  75        allow_signal(SIGKILL);
  76        allow_signal(SIGSTOP);
  77        allow_signal(SIGCONT);
  78
  79        c->gc_task = current;
  80        complete(&c->gc_thread_start);
  81
  82        set_user_nice(current, 10);
  83
  84        set_freezable();
  85        for (;;) {
  86                allow_signal(SIGHUP);
  87        again:
  88                spin_lock(&c->erase_completion_lock);
  89                if (!jffs2_thread_should_wake(c)) {
  90                        set_current_state (TASK_INTERRUPTIBLE);
  91                        spin_unlock(&c->erase_completion_lock);
  92                        D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
  93                        schedule();
  94                } else
  95                        spin_unlock(&c->erase_completion_lock);
  96
  97
  98                /* This thread is purely an optimisation. But if it runs when
  99                   other things could be running, it actually makes things a
 100                   lot worse. Use yield() and put it at the back of the runqueue
 101                   every time. Especially during boot, pulling an inode in
 102                   with read_inode() is much preferable to having the GC thread
 103                   get there first. */
 104                yield();
 105
 106                /* Put_super will send a SIGKILL and then wait on the sem.
 107                 */
 108                while (signal_pending(current) || freezing(current)) {
 109                        siginfo_t info;
 110                        unsigned long signr;
 111
 112                        if (try_to_freeze())
 113                                goto again;
 114
 115                        signr = dequeue_signal_lock(current, &current->blocked, &info);
 116
 117                        switch(signr) {
 118                        case SIGSTOP:
 119                                D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n"));
 120                                set_current_state(TASK_STOPPED);
 121                                schedule();
 122                                break;
 123
 124                        case SIGKILL:
 125                                D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
 126                                goto die;
 127
 128                        case SIGHUP:
 129                                D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGHUP received.\n"));
 130                                break;
 131                        default:
 132                                D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr));
 133                        }
 134                }
 135                /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
 136                disallow_signal(SIGHUP);
 137
 138                D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
 139                if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
 140                        printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
 141                        goto die;
 142                }
 143        }
 144 die:
 145        spin_lock(&c->erase_completion_lock);
 146        c->gc_task = NULL;
 147        spin_unlock(&c->erase_completion_lock);
 148        complete_and_exit(&c->gc_thread_exit, 0);
 149}
 150