linux/mm/pdflush.c
<<
>>
Prefs
   1/*
   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
  33static 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 */
  48static LIST_HEAD(pdflush_list);
  49static 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 */
  58int nr_pdflush_threads = 0;
  59
  60/*
  61 * The time at which the pdflush thread pool last went empty
  62 */
  63static 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 */
  84struct 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
  92static int __pdflush(struct pdflush_work *my_work)
  93{
  94        current->flags |= PF_FLUSHER | PF_SWAPWRITE;
  95        my_work->fn = NULL;
  96        my_work->who = current;
  97        INIT_LIST_HEAD(&my_work->list);
  98
  99        spin_lock_irq(&pdflush_lock);
 100        nr_pdflush_threads++;
 101        for ( ; ; ) {
 102                struct pdflush_work *pdf;
 103
 104                set_current_state(TASK_INTERRUPTIBLE);
 105                list_move(&my_work->list, &pdflush_list);
 106                my_work->when_i_went_to_sleep = jiffies;
 107                spin_unlock_irq(&pdflush_lock);
 108                schedule();
 109                try_to_freeze();
 110                spin_lock_irq(&pdflush_lock);
 111                if (!list_empty(&my_work->list)) {
 112                        /*
 113                         * Someone woke us up, but without removing our control
 114                         * structure from the global list.  swsusp will do this
 115                         * in try_to_freeze()->refrigerator().  Handle it.
 116                         */
 117                        my_work->fn = NULL;
 118                        continue;
 119                }
 120                if (my_work->fn == NULL) {
 121                        printk("pdflush: bogus wakeup\n");
 122                        continue;
 123                }
 124                spin_unlock_irq(&pdflush_lock);
 125
 126                (*my_work->fn)(my_work->arg0);
 127
 128                /*
 129                 * Thread creation: For how long have there been zero
 130                 * available threads?
 131                 */
 132                if (jiffies - last_empty_jifs > 1 * HZ) {
 133                        /* unlocked list_empty() test is OK here */
 134                        if (list_empty(&pdflush_list)) {
 135                                /* unlocked test is OK here */
 136                                if (nr_pdflush_threads < MAX_PDFLUSH_THREADS)
 137                                        start_one_pdflush_thread();
 138                        }
 139                }
 140
 141                spin_lock_irq(&pdflush_lock);
 142                my_work->fn = NULL;
 143
 144                /*
 145                 * Thread destruction: For how long has the sleepiest
 146                 * thread slept?
 147                 */
 148                if (list_empty(&pdflush_list))
 149                        continue;
 150                if (nr_pdflush_threads <= MIN_PDFLUSH_THREADS)
 151                        continue;
 152                pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
 153                if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) {
 154                        /* Limit exit rate */
 155                        pdf->when_i_went_to_sleep = jiffies;
 156                        break;                                  /* exeunt */
 157                }
 158        }
 159        nr_pdflush_threads--;
 160        spin_unlock_irq(&pdflush_lock);
 161        return 0;
 162}
 163
 164/*
 165 * Of course, my_work wants to be just a local in __pdflush().  It is
 166 * separated out in this manner to hopefully prevent the compiler from
 167 * performing unfortunate optimisations against the auto variables.  Because
 168 * these are visible to other tasks and CPUs.  (No problem has actually
 169 * been observed.  This is just paranoia).
 170 */
 171static int pdflush(void *dummy)
 172{
 173        struct pdflush_work my_work;
 174        cpumask_t cpus_allowed;
 175
 176        /*
 177         * pdflush can spend a lot of time doing encryption via dm-crypt.  We
 178         * don't want to do that at keventd's priority.
 179         */
 180        set_user_nice(current, 0);
 181
 182        /*
 183         * Some configs put our parent kthread in a limited cpuset,
 184         * which kthread() overrides, forcing cpus_allowed == CPU_MASK_ALL.
 185         * Our needs are more modest - cut back to our cpusets cpus_allowed.
 186         * This is needed as pdflush's are dynamically created and destroyed.
 187         * The boottime pdflush's are easily placed w/o these 2 lines.
 188         */
 189        cpus_allowed = cpuset_cpus_allowed(current);
 190        set_cpus_allowed(current, cpus_allowed);
 191
 192        return __pdflush(&my_work);
 193}
 194
 195/*
 196 * Attempt to wake up a pdflush thread, and get it to do some work for you.
 197 * Returns zero if it indeed managed to find a worker thread, and passed your
 198 * payload to it.
 199 */
 200int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
 201{
 202        unsigned long flags;
 203        int ret = 0;
 204
 205        BUG_ON(fn == NULL);     /* Hard to diagnose if it's deferred */
 206
 207        spin_lock_irqsave(&pdflush_lock, flags);
 208        if (list_empty(&pdflush_list)) {
 209                spin_unlock_irqrestore(&pdflush_lock, flags);
 210                ret = -1;
 211        } else {
 212                struct pdflush_work *pdf;
 213
 214                pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
 215                list_del_init(&pdf->list);
 216                if (list_empty(&pdflush_list))
 217                        last_empty_jifs = jiffies;
 218                pdf->fn = fn;
 219                pdf->arg0 = arg0;
 220                wake_up_process(pdf->who);
 221                spin_unlock_irqrestore(&pdflush_lock, flags);
 222        }
 223        return ret;
 224}
 225
 226static void start_one_pdflush_thread(void)
 227{
 228        kthread_run(pdflush, NULL, "pdflush");
 229}
 230
 231static int __init pdflush_init(void)
 232{
 233        int i;
 234
 235        for (i = 0; i < MIN_PDFLUSH_THREADS; i++)
 236                start_one_pdflush_thread();
 237        return 0;
 238}
 239
 240module_init(pdflush_init);
 241
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.