Mercurial > ecos
comparison packages/fs/jffs2/current/src/background.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 /* | |
| 2 * JFFS2 -- Journalling Flash File System, Version 2. | |
| 3 * | |
| 4 * Copyright (C) 2001 Red Hat, Inc. | |
| 5 * | |
| 6 * Created by David Woodhouse <dwmw2@cambridge.redhat.com> | |
| 7 * | |
| 8 * For licensing information, see the file 'LICENCE' in this directory. | |
| 9 * | |
| 10 * $Id: background.c,v 1.16 2001/10/08 09:22:38 dwmw2 Exp $ | |
| 11 * | |
| 12 */ | |
| 13 | |
| 14 #define __KERNEL_SYSCALLS__ | |
| 15 | |
| 16 #include <linux/kernel.h> | |
| 17 #include <linux/sched.h> | |
| 18 #include <linux/unistd.h> | |
| 19 #include <linux/jffs2.h> | |
| 20 #include <linux/mtd/mtd.h> | |
| 21 #include <linux/interrupt.h> | |
| 22 #include <linux/completion.h> | |
| 23 #include "nodelist.h" | |
| 24 | |
| 25 | |
| 26 static int jffs2_garbage_collect_thread(void *); | |
| 27 static int thread_should_wake(struct jffs2_sb_info *c); | |
| 28 | |
| 29 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) | |
| 30 { | |
| 31 spin_lock_bh(&c->erase_completion_lock); | |
| 32 if (c->gc_task && thread_should_wake(c)) | |
| 33 send_sig(SIGHUP, c->gc_task, 1); | |
| 34 spin_unlock_bh(&c->erase_completion_lock); | |
| 35 } | |
| 36 | |
| 37 /* This must only ever be called when no GC thread is currently running */ | |
| 38 int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) | |
| 39 { | |
| 40 pid_t pid; | |
| 41 int ret = 0; | |
| 42 | |
| 43 if (c->gc_task) | |
| 44 BUG(); | |
| 45 | |
| 46 init_MUTEX_LOCKED(&c->gc_thread_start); | |
| 47 init_completion(&c->gc_thread_exit); | |
| 48 | |
| 49 pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); | |
| 50 if (pid < 0) { | |
| 51 printk(KERN_WARNING "fork failed for JFFS2 garbage collect thread: %d\n", -pid); | |
| 52 complete(&c->gc_thread_exit); | |
| 53 ret = pid; | |
| 54 } else { | |
| 55 /* Wait for it... */ | |
| 56 D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); | |
| 57 down(&c->gc_thread_start); | |
| 58 } | |
| 59 | |
| 60 return ret; | |
| 61 } | |
| 62 | |
| 63 void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) | |
| 64 { | |
| 65 spin_lock_bh(&c->erase_completion_lock); | |
| 66 if (c->gc_task) { | |
| 67 D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); | |
| 68 send_sig(SIGKILL, c->gc_task, 1); | |
| 69 } | |
| 70 spin_unlock_bh(&c->erase_completion_lock); | |
| 71 wait_for_completion(&c->gc_thread_exit); | |
| 72 } | |
| 73 | |
| 74 static int jffs2_garbage_collect_thread(void *_c) | |
| 75 { | |
| 76 struct jffs2_sb_info *c = _c; | |
| 77 | |
| 78 daemonize(); | |
| 79 current->tty = NULL; | |
| 80 c->gc_task = current; | |
| 81 up(&c->gc_thread_start); | |
| 82 | |
| 83 sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); | |
| 84 | |
| 85 /* FIXME in the 2.2 backport */ | |
| 86 current->nice = 10; | |
| 87 | |
| 88 for (;;) { | |
| 89 spin_lock_irq(¤t->sigmask_lock); | |
| 90 siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); | |
| 91 recalc_sigpending(current); | |
| 92 spin_unlock_irq(¤t->sigmask_lock); | |
| 93 | |
| 94 if (!thread_should_wake(c)) { | |
| 95 set_current_state (TASK_INTERRUPTIBLE); | |
| 96 D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); | |
| 97 /* Yes, there's a race here; we checked thread_should_wake() before | |
| 98 setting current->state to TASK_INTERRUPTIBLE. But it doesn't | |
| 99 matter - We don't care if we miss a wakeup, because the GC thread | |
| 100 is only an optimisation anyway. */ | |
| 101 schedule(); | |
| 102 } | |
| 103 | |
| 104 if (current->need_resched) | |
| 105 schedule(); | |
| 106 | |
| 107 /* Put_super will send a SIGKILL and then wait on the sem. | |
| 108 */ | |
| 109 while (signal_pending(current)) { | |
| 110 siginfo_t info; | |
| 111 unsigned long signr; | |
| 112 | |
| 113 spin_lock_irq(¤t->sigmask_lock); | |
| 114 signr = dequeue_signal(¤t->blocked, &info); | |
| 115 spin_unlock_irq(¤t->sigmask_lock); | |
| 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 spin_lock_bh(&c->erase_completion_lock); | |
| 127 c->gc_task = NULL; | |
| 128 spin_unlock_bh(&c->erase_completion_lock); | |
| 129 complete_and_exit(&c->gc_thread_exit, 0); | |
| 130 | |
| 131 case SIGHUP: | |
| 132 D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGHUP received.\n")); | |
| 133 break; | |
| 134 default: | |
| 135 D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr)); | |
| 136 | |
| 137 } | |
| 138 } | |
| 139 /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ | |
| 140 spin_lock_irq(¤t->sigmask_lock); | |
| 141 siginitsetinv (¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); | |
| 142 recalc_sigpending(current); | |
| 143 spin_unlock_irq(¤t->sigmask_lock); | |
| 144 | |
| 145 D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n")); | |
| 146 jffs2_garbage_collect_pass(c); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 static int thread_should_wake(struct jffs2_sb_info *c) | |
| 151 { | |
| 152 D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n", | |
| 153 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size)); | |
| 154 if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && | |
| 155 c->dirty_size > c->sector_size) | |
| 156 return 1; | |
| 157 else | |
| 158 return 0; | |
| 159 } |
