OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [mm/] [pdflush.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * mm/pdflush.c - worker threads for writing back filesystem data
3
 *
4
 * Copyright (C) 2002, Linus Torvalds.
5
 *
6
 * 09Apr2002    akpm@zip.com.au
7
 *              Initial version
8
 * 29Feb2004    kaos@sgi.com
9
 *              Move worker thread creation to kthread to avoid chewing
10
 *              up stack space with nested calls to kernel_thread.
11
 */
12
 
13
#include <linux/sched.h>
14
#include <linux/list.h>
15
#include <linux/signal.h>
16
#include <linux/spinlock.h>
17
#include <linux/gfp.h>
18
#include <linux/init.h>
19
#include <linux/module.h>
20
#include <linux/fs.h>           // Needed by writeback.h
21
#include <linux/writeback.h>    // Prototypes pdflush_operation()
22
#include <linux/kthread.h>
23
#include <linux/cpuset.h>
24
#include <linux/freezer.h>
25
 
26
 
27
/*
28
 * Minimum and maximum number of pdflush instances
29
 */
30
#define MIN_PDFLUSH_THREADS     2
31
#define MAX_PDFLUSH_THREADS     8
32
 
33
static void start_one_pdflush_thread(void);
34
 
35
 
36
/*
37
 * The pdflush threads are worker threads for writing back dirty data.
38
 * Ideally, we'd like one thread per active disk spindle.  But the disk
39
 * topology is very hard to divine at this level.   Instead, we take
40
 * care in various places to prevent more than one pdflush thread from
41
 * performing writeback against a single filesystem.  pdflush threads
42
 * have the PF_FLUSHER flag set in current->flags to aid in this.
43
 */
44
 
45
/*
46
 * All the pdflush threads.  Protected by pdflush_lock
47
 */
48
static LIST_HEAD(pdflush_list);
49
static DEFINE_SPINLOCK(pdflush_lock);
50
 
51
/*
52
 * The count of currently-running pdflush threads.  Protected
53
 * by pdflush_lock.
54
 *
55
 * Readable by sysctl, but not writable.  Published to userspace at
56
 * /proc/sys/vm/nr_pdflush_threads.
57
 */
58
int nr_pdflush_threads = 0;
59
 
60
/*
61
 * The time at which the pdflush thread pool last went empty
62
 */
63
static unsigned long last_empty_jifs;
64
 
65
/*
66
 * The pdflush thread.
67
 *
68
 * Thread pool management algorithm:
69
 *
70
 * - The minimum and maximum number of pdflush instances are bound
71
 *   by MIN_PDFLUSH_THREADS and MAX_PDFLUSH_THREADS.
72
 *
73
 * - If there have been no idle pdflush instances for 1 second, create
74
 *   a new one.
75
 *
76
 * - If the least-recently-went-to-sleep pdflush thread has been asleep
77
 *   for more than one second, terminate a thread.
78
 */
79
 
80
/*
81
 * A structure for passing work to a pdflush thread.  Also for passing
82
 * state information between pdflush threads.  Protected by pdflush_lock.
83
 */
84
struct pdflush_work {
85
        struct task_struct *who;        /* The thread */
86
        void (*fn)(unsigned long);      /* A callback function */
87
        unsigned long arg0;             /* An argument to the callback */
88
        struct list_head list;          /* On pdflush_list, when idle */
89
        unsigned long when_i_went_to_sleep;
90
};
91
 
92
static int __pdflush(struct pdflush_work *my_work)
93
{
94
        current->flags |= PF_FLUSHER | PF_SWAPWRITE;
95
        set_freezable();
96
        my_work->fn = NULL;
97
        my_work->who = current;
98
        INIT_LIST_HEAD(&my_work->list);
99
 
100
        spin_lock_irq(&pdflush_lock);
101
        nr_pdflush_threads++;
102
        for ( ; ; ) {
103
                struct pdflush_work *pdf;
104
 
105
                set_current_state(TASK_INTERRUPTIBLE);
106
                list_move(&my_work->list, &pdflush_list);
107
                my_work->when_i_went_to_sleep = jiffies;
108
                spin_unlock_irq(&pdflush_lock);
109
                schedule();
110
                try_to_freeze();
111
                spin_lock_irq(&pdflush_lock);
112
                if (!list_empty(&my_work->list)) {
113
                        /*
114
                         * Someone woke us up, but without removing our control
115
                         * structure from the global list.  swsusp will do this
116
                         * in try_to_freeze()->refrigerator().  Handle it.
117
                         */
118
                        my_work->fn = NULL;
119
                        continue;
120
                }
121
                if (my_work->fn == NULL) {
122
                        printk("pdflush: bogus wakeup\n");
123
                        continue;
124
                }
125
                spin_unlock_irq(&pdflush_lock);
126
 
127
                (*my_work->fn)(my_work->arg0);
128
 
129
                /*
130
                 * Thread creation: For how long have there been zero
131
                 * available threads?
132
                 */
133
                if (jiffies - last_empty_jifs > 1 * HZ) {
134
                        /* unlocked list_empty() test is OK here */
135
                        if (list_empty(&pdflush_list)) {
136
                                /* unlocked test is OK here */
137
                                if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)
138
                                        start_one_pdflush_thread();
139
                        }
140
                }
141
 
142
                spin_lock_irq(&pdflush_lock);
143
                my_work->fn = NULL;
144
 
145
                /*
146
                 * Thread destruction: For how long has the sleepiest
147
                 * thread slept?
148
                 */
149
                if (list_empty(&pdflush_list))
150
                        continue;
151
                if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
152
                        continue;
153
                pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
154
                if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) {
155
                        /* Limit exit rate */
156
                        pdf->when_i_went_to_sleep = jiffies;
157
                        break;                                  /* exeunt */
158
                }
159
        }
160
        nr_pdflush_threads--;
161
        spin_unlock_irq(&pdflush_lock);
162
        return 0;
163
}
164
 
165
/*
166
 * Of course, my_work wants to be just a local in __pdflush().  It is
167
 * separated out in this manner to hopefully prevent the compiler from
168
 * performing unfortunate optimisations against the auto variables.  Because
169
 * these are visible to other tasks and CPUs.  (No problem has actually
170
 * been observed.  This is just paranoia).
171
 */
172
static int pdflush(void *dummy)
173
{
174
        struct pdflush_work my_work;
175
        cpumask_t cpus_allowed;
176
 
177
        /*
178
         * pdflush can spend a lot of time doing encryption via dm-crypt.  We
179
         * don't want to do that at keventd's priority.
180
         */
181
        set_user_nice(current, 0);
182
 
183
        /*
184
         * Some configs put our parent kthread in a limited cpuset,
185
         * which kthread() overrides, forcing cpus_allowed == CPU_MASK_ALL.
186
         * Our needs are more modest - cut back to our cpusets cpus_allowed.
187
         * This is needed as pdflush's are dynamically created and destroyed.
188
         * The boottime pdflush's are easily placed w/o these 2 lines.
189
         */
190
        cpus_allowed = cpuset_cpus_allowed(current);
191
        set_cpus_allowed(current, cpus_allowed);
192
 
193
        return __pdflush(&my_work);
194
}
195
 
196
/*
197
 * Attempt to wake up a pdflush thread, and get it to do some work for you.
198
 * Returns zero if it indeed managed to find a worker thread, and passed your
199
 * payload to it.
200
 */
201
int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
202
{
203
        unsigned long flags;
204
        int ret = 0;
205
 
206
        BUG_ON(fn == NULL);     /* Hard to diagnose if it's deferred */
207
 
208
        spin_lock_irqsave(&pdflush_lock, flags);
209
        if (list_empty(&pdflush_list)) {
210
                spin_unlock_irqrestore(&pdflush_lock, flags);
211
                ret = -1;
212
        } else {
213
                struct pdflush_work *pdf;
214
 
215
                pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
216
                list_del_init(&pdf->list);
217
                if (list_empty(&pdflush_list))
218
                        last_empty_jifs = jiffies;
219
                pdf->fn = fn;
220
                pdf->arg0 = arg0;
221
                wake_up_process(pdf->who);
222
                spin_unlock_irqrestore(&pdflush_lock, flags);
223
        }
224
        return ret;
225
}
226
 
227
static void start_one_pdflush_thread(void)
228
{
229
        kthread_run(pdflush, NULL, "pdflush");
230
}
231
 
232
static int __init pdflush_init(void)
233
{
234
        int i;
235
 
236
        for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
237
                start_one_pdflush_thread();
238
        return 0;
239
}
240
 
241
module_init(pdflush_init);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.